- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
var actions = new List<Action>();
foreach (var i in Enumerable.Range(1, 3))
{
actions.Add(() => Console.WriteLine(i));
}
foreach (var action in actions)
{
action();
}
Нашли или выдавили из себя код, который нельзя назвать нормальным, на который без улыбки не взглянешь? Не торопитесь его удалять или рефакторить, — запостите его на говнокод.ру, посмеёмся вместе!
+3
var actions = new List<Action>();
foreach (var i in Enumerable.Range(1, 3))
{
actions.Add(() => Console.WriteLine(i));
}
foreach (var action in actions)
{
action();
}
По мотивам https://govnokod.ru/11946
Просто форкнул и запустил старый пример LispGovno (мир ему)
Старый пример: https://ideone.com/RaiHr
Новый пример: https://ideone.com/M1ducs
Однако получил совершенно другой результат.
https://ideone.com/Y0YAKW
Но тут нужно учитывать что в «Йажа» питузы учёные, ходят к электричеству подключенные.
Учились на шишках C# и сделали всё, чтобы не обосраться.
И неявный final на захватываемых переменных. И даже с var, несмотря на мутацию компилируется и работает очевидным образом.
Сишка плохая. В Сишке нет переносимости программ, код на разных платформах и компиляторах работает по-разному. UB там.
А вот в managed environment, где код исполняется виртуальной машиной такой проблемы нет. Всё однообразно и предсказуемо.
«Write once — run everywhere».
Но у нас все ходы записаны в ideone. И маркетинговая методичка сектантов — просто bullshit.
Речь о CLR = Common Language Runtime в случае C# и о JVM = Java Virtual Machine в случае Java, конечно же.
https://en.wikipedia.org/wiki/Managed_code
https://ru.wikipedia.org/wiki/Управляемый_код
В «Minetest», опенсурсном воксельном движке, для которого ТОРТ выучил «Lua», дно мира находится на 30_912 метров ниже уровня моря, это пиздец как долго надо туда копать: если один блок ломается за секунду, то «бурение» до самых недр майнтеста займёт около восьми с половиной часов!
Ну вообще говоря спека LLVM описывает поведение какой-то абстрактной машины, которая не существует в реальности. А раз не существует -- значит виртуальная.
То что потом это поведение пытаются воспроизвести на реальной машине, сгенерив похожий по смыслу код, сути не меняет.
А что если и реальности на самом-то деле не существует? Может это все мой сон, и тогда все машины - виртуальные.
Кстати там еще в том сне Volkov Commander (или Norton Commander? Но я почему-то про Volkov подумал) какой-то был на старом IBM-совместимом ПК. Вот то точно виртуальная машина.
https://dev.by/news/intervyu-s-krisom-kasperski-aka-mysch-h
> Мне-то лично пофиг, если меня убьют. Я просто проснусь и всё. А вот вам, вероятно, не пофиг.
А кто это?
В "Planescape: Torment" я не играл, хотя и читал примерно, о чем там сюжет. Мне сейчас уже слишком лень читать столько текста и столько диалогов прокликивать.
Вот в "Arcanum" я например играл, там можно было на помойке из мусорок доставать ботинки и потом их продавать. А еще крафтить линолеумный вентилятор всякую хуйню из запчастей с мусорки.
https://ru.wikipedia.org/wiki/Colossal_Cave_Adventure
http://instead.hugeping.ru/
там кстати текстовые квесты из "Космические рейнджеры" запускать можно. http://instead-games.ru/games/screenshots/20140314112011710.jpg
Другое дело, что текстовые квесты не нужны
Loom, SpaceQuest, вот это всё
Хотя во многих играх они и правда унылое пафосное г-но, как будто посмотрел Mockbuster
> где код исполняется виртуальной машиной такой проблемы нет
Переносимость. Когда ваш жабий байткод будет запускаться на питонячей VM, с чем, по вашим словам, проблем не должно быть, тогда и приходите.
https://ru.wikipedia.org/wiki/Parrot
Компилятор из «Mono» вернул такой же результат.
.NET 2.0 не смог найти «Linq».
Компилятор из .NET 3.5 возвращает другой результат:
Итого: .NET 3.5 с четвёркой вообще несовместим.
jsников любят обсирать за var.
Однако даже у ненавидимых всеми скриптухов хватило ума чтобы не ломать устойчивое поведение, не порождать Undefined Behavior.
А просто ввести новый кейворд let.
Надо ещё в новомодном «.Net Core» проверить.
«Portable.Net»/«dotGNU» сгнил, не дожив до новых версий платформы.
Какие ещё есть реализации?
https://ideone.com/Y0YAKW
Хз, я не настоящий сварщик. Знаю только Mono и .NET
https://www.java.com/ru/
This site requires JavaScript to be enabled.
похрюкал
Фрагмент из 4.6:
Порядок нескольких действий изменился. Надо будет разобраться, как он цикл организовал, тогда станет ясно, почему такие результаты.
Вроде в 3.5 конструктор вызывается до цикла (поэтому три копии одного результата), а в 4.x конструктор вызывается в цикле (поэтому результаты разные).
https://ideone.com/EMQBA
Тогда и в 3.5 выводит 1 2 3
Багор ведь остался. Лаже не надо класс со ссылкой городить.
То есть теперь (var i in Enumerable.Range(1, 3)) передаёт i в замыкание по значению. И выводит 1 2 3
А у for(var i = 0; i<3; i++) передаёт i в замыкание по ссылке выводит, по-прежнему, 3 3 3.
https://ideone.com/cbD8Kv
Пиздец. Просто пиздец.
Она просекает что мутабельный питух хочет пролезть в замыкание и не даёт ему этого сделать.
То есть в «Йажа» допустима педерача сложного объекта по ссылке (массив, объект), но явно видно что это ссылка.
А мутация захватываемого питуха просто запрещена.
«Йажа» конечно делали питузы учёные, а мы им массивы мучёные.
https://ideone.com/rGrzw3
Чтобы анскильным отбросам было проще жить?
Аналогично C#
https://ideone.com/LlUtqP
Программа, собранная компилятором из .NET 3.5:
По ходу дела мутируя его. Логика как в этом примере: https://govnokod.ru/27628#comment666384 у меня тоже один объект Bagor.
Test.<>c__DisplayClass2 <>c__DisplayClass2 = new Test.<>c__DisplayClass2();
Во-втором случае это три разных объекта. На каждой итерации создаётся уникальный питух.
Возвращает 1 2 3:
https://ideone.com/2TDMMb
В «PHP» мы явно указываем, как захватывать $i: по ссылке или по значению. Я захватил по значению.
https://ideone.com/WDdijn
И никакой тебе пирдоли, неопределённых поведений.
Вот что значит язык для белых людей.
https://govnokod.ru/27509#comment664590
https://govnokod.ru/27091#comment593020
Джавашки меня смутили со своим ->
У C#, PHP, JS замыкание =>
> он писал про получение свойств объектов
Это как в Сишке доступ к полю указателя?
Это как {} в «Паскале» означает комментарий, а в языках с сиподобным синтаксисом — блок.
> Это как в Сишке доступ к полю указателя?
Ну да, скосплеили ->, только в «PHP» явно разыменовывать ничего не нужно, потому что тут везде сахар для ссылок.
Не хочу занудствовать, но вроде изначально у Вирта никаких { } не было. Только (* *).
Это грудь или опущенные глаза?
https://ideone.com/SVYzuj
Как «триграфы» в Сишке.
Думаю они и появились по схожим причинам (урезанные кодировки без этих символов).
https://govnokod.ru/21181
Спокойной ночи.
https://www.php.net/manual/ru/functions.arrow.php
Кстати, они хватают по значению, а не по ссылке. Т. е. стрелочная функция вывела бы 1 2 3.
Кроме крестов и «PHP», ещё где-нибудь контекст для захвата указывается явно?
IEnumerator может быть не только детерминированный Range(1, 3), а и внешние вызовы ололо-linq, которое например лезет в базу или получает по http.
А т.к. RAII нет, то generic реализация макроса всегда делает его Dispose. По принципу: «абы чего не вышло».
foreach тоже синтаксический сахар, который внутри себя вызывает обычный итератор.
C одной стороны MS конечно молодцы, что оперируя препроцессором, быстро нагородили в языке синтаксического сахарку не меняя существующего бат-кода.
Этот же подход мы видели в «TypeScript», когда из пары строк генерятся сотни строк вореционной JS-дрисни.
https://govnokod.ru/27615#comment661036
С другой странно что сишников ругают за препроцессорный подход. Хотя они по сути делают абсолютно ТО ЖЕ САМОЕ,
Думаю совещание в Редмонде по новым фичам C# выглядело примерно так:
Смотри, джависты, они тебе расширяться мешают.
А я вот, давай я здесь насру, и джависты все прилетят сюда, и мы их наймём, слышишь?
И тебе тогда спать, ой, спать будет хорошо. Давай? Я насру функционалом, а джависты все прилетят, сюда, к нам.
Ну, куда им ещё, ихнее место-то тока здесь, и… ооой… хочешь, я насру здесь?И джависты, и мы их наймём! Ну что, срать?
Просто у них есть сырцы и какие-то, грубо говря, символы для дебага, и всё
не?
Это не выхлоп компилятора.
Это раскрытие синтаксического сахара препроцессором а-ля Сишка.
В одном случае оно из одного «TypeScript» кода (с классами, типами форычами и елдаками) генерит «JavaScript», который тоже валидный «TypeScript» код.
В случае .NET оно из одного C# кода (с форычами и лямбдами) генерит другой, тоже валидный C#-код.
Только он сильно раздувается и не содержит новых блестящих форычей, лямбд, елдаков, вместо него появляется разный скучный и олдскульный бойлерплейт типа while, флагов, итд.
По сути это ничем не отличается от макросов (местами жутких), которые пишет j123123.
Они тоже раскрывают няшные макросы на Сишке в чудовищные пиздецы на той же самой Сишке.
Только в случае C# и TS такие макросы из коробки встроены в язык. И написать свои нельзя.
Зачем мне знать что он выхлпнул?
Это как магнленные имена в С++ читать.
Макросы j1234 ужасны не выхлопом, а своим кодом. Если его не читать, то он ок.
Я уверен, что использовал в сишке ужасные макросы, и даже не знал, что пиша `Foo()`` я использую на самом деле ужасный макрос
> Зачем мне знать что он выхлпнул?
Пока абстракция работает думаю незачем.
Но только она начинает подтекать и вести себя непредсказуемо, как в нашем случае.
Тогда всё-равно приходится лезть в кишки и смотреть весь этот неявный ужас.
Чтобы понять как она работает, и использовать её без багров.
> и это не препроцессор бы транспилировал, а компилятор компилировал, то было бы лучше?
Для пирформанса возможно и лучше.
В «Йажа» foreach по списку до сих пор в несколько раз медленее анскильных импераций :
В C# как мы видим тоже самое.
foreach раскрывается в унылый питератор, а не супербыстрый опкод обхода с минимальной перепитушнёй.
Хотя наоборот эти циклы должны быть супероптимизированы.
Т.к. кишки явной индексации спрятаны от пользователя и можно применять целый набор оптимизаций: обходить массив оптимальном направлении, убирать array bounds checks без пирдолинга с доказательствами, итд.
по сравнению с сишкообразным фором на йаже
Джит умный, а джавак -- нет
Альзо, если там List а не массив, то компилятор и не знает заранее, там же интерфес
Код:
Байткод (только foo()):
forEach() развернулся в 00000014—0000003D.
Только на 0000003D лишний nop добавился.
Даже в «Питоне» осилили итераторы без двойной работы, а в ЙАЖЕ до сих пор на каждой итерации дублируют логику в next() и hasNext().
за счет исключения
в яже было бы еще хужее
А вот классические ЙАЖАвские итераторы выглядят примерно так:
Как результат — условие в hasNext() проверяется джва раза на каждой итерации. И умного оптимизирующего компилятора (вроде сишного или крестового), который бы это определил и вырезал лишние проверки, в ЙАЖУ не завезли. Пиздец.
Зацени браваду джавашни
> However, Java is one of the fastest and most energy-efficient object-oriented language. Interpreted languages like Perl, Python, and Ruby were among the least energy efficient
https://jaxenter.com/energy-efficient-programming-languages-137264.html
https://jaxenter.com/wp-content/uploads/2017/09/energy-efficient-languages-768x689.png
https://jaxenter.com/wp-content/uploads/2017/09/energy-efficient-languages-2-768x368.png
И под конец:
> Well, yes. C is the clear winner across all the fields.
> invokevirtual int java.lang.Number.intValue()
А вот автоанбоксинг виртуальным методом (опять на суперклассе с 10ю наследниками: Long, Byte, Integer, Float, Double, итд) это прощай пирформанс.
Причём два ВИРТУАЛЬНЫХ вывоза: invokeinterface.
> 00000015 : invokeinterface boolean java.util.Iterator.hasNext(), 1
> 0000001E : invokeinterface java.lang.Object java.util.Iterator.next(), 1
Да, Йажа умеет оптимизировать виртуальные методы.
Но только ПРИ УСЛОВИИ что число возможных наследников 1 или 2.
То есть у интерфейса имеется 1 или 2 ральзации, не больше.
А всяких разных implements Iterator только в jre несколько сотен.
Но может с тех пор что-то улучшилось.
Хорошо, что в крестах вся эта питушня с итераторами работает без виртуальных таблиц
Неправда. Зачастую знает.
Но даже один раз сделать instanceof RandomAccess перед циклом будет быстрее чем плодить лишний объект и каждый раз дрочить hasNext().
instanceof is very cheap.
Результат:
Так нормально проходит по underlying массиву через «aaload».
А мы про лист
https://github.com/JetBrains/kotlin/blob/1.0.1/core/builtins/native/kotlin/Array.kt
Смотри:
Есть интерфейс `java.lang.Iterable`
Его наследники ArrayList, LinkedList, Set, еще какая-то дрисня, и код может его получать и вообще не знать что у тебя там ArrayList (то есть массив по сути) а не LinkedList.
А Array его не наследует ни в джове, ни в котлине
Потому универасальный код не написать, и потому
`Array.forEach` это ЯВНО массив, и его можно оптимизнуть
про рендом аксесс согласен
Вообще мне тут больше нравится то, что сделали крестобляди
У них есть много сортов интераторов с разными свойствами, и можно в функции явно написать "суй суда итератор с рендом аксессом" и туда лист не всунется просто
ну ща гост проверит
Соснул.
А если сделать Ctrl+LMB по «forEach», то ожидаемо придём в _Collections.kt и увидим extension-метод:
UPD: не тот метод скопипастил.
И тут мы приходим к тому, о чём я уже говорил.
Йажа-сектант это в 95% мразь, а в 5% просто обманутый/неразобравшийся человек.
Они не сделали быстрый форыч.
Они просто обмазали сахарком унылый питератор.
И в этом и заключается фокус.
> checkIndexOverflow(index++)
Блять. БЛЯТЬ. Две проверки мало. Нужно сделать ТРИ!
Ему ведь надо быть совместимым с яжей
А array ([]) в яжа это не часть Collections
Йажа тоже не генерит оптимальный байт-код, который чекает что это RandomAccess.
И тоже неспособна сделать нормальный for без итератора.
То есть обосрались, since 1.4 предлагая на каждый обход списка для оптимальности делать два цикла и instanceof RandomAccess руками.
Угадайте язык и почему так
Так точно.
Хотя в компайл тайме информации об этом достаточно.
https://docs.oracle.com/javase/7/docs/api/java/util/RandomAccess.html
Со времён 1.4 всё известно. Извинити, руки из жопы, вот вам ещё тонна синтаксической сахарозы.
Какой багор )))
Оптимизатор не замечает, что там в итераторе тупо циферка, которая инкрементится? Тут вроде даже не надо магических интерфейсов, банальный инлайн свернёт второй цикл к первому.
А как же его заинлайнить, если приходит List непонятно какого типа, а next/hasNext виртуальные методы в интерфейсе Iterator?
Нет уж, батенька извольте invokeinterface с таблицей вирутальных функций. Всё как полагается.
https://govnokod.ru/27628#comment666723
Ну я так понимаю, он не заинлайнит и если тип понятный и описан строчкой выше?
> он не заинлайнит и если тип понятный и описан строчкой выше
Возможно и заинлайнит.
Но опять же тип ArrayList, а он возвращает не ArrayList.Iterator<T>, а женерик Iterator<T>.
То есть...
... надо заинлайнить list.iterator() и тогда мы узнаем, что там ArrayList.Iterator, у которого все методы тривиальны.
Они-то тривиальны, но из реализации ArrayList мы узнаём что в сигнатуре iterator() НЕ УКАЗАН конкретный тип реализации:
И подобных итераторов там десятки.
Например hasNext() дёргает size(). Как и положено всякой школоте размер списка проверяется на каждой итерации.
При том что по умолчанию эти классы не расчитаны на многопоточное использование.
Этому коду на «Говнокод» самое место.
ЧуднО он говорил: военкомод…
Так говорил, что смейся до упада.
Компилялось в отлично оптимизированный код (чуть ли до уровня прямого движения уко-ко-ко-зателей), а вот на чём-то вроде
Компилятор эпично обсирался и врубал не только bound-checking, но ещё и на каждой имперации вычислял «list.Length - 1» (кажется, аж с вызовом метода)!
Он выдаёт код без лямбд и без форычей из кишков «LLVM».
Кнопка с бегущим питухом страусом. Мне уже нравится.
https://github.com/andreasfertig/cppinsights
Можно собрать у себя и прогонять через него проекты для C++17 и C++20, чтобы они потом на другой платформе собирались древним C++98. Ну или просто изучать, как устроены новые возможности языка.
https://govnokod.ru/27628#comment666390 Вроде логика одна и та же.
К слову, в шарпе этот "фикс" не особо то и нужен, всегда можно было скопировать i в локалку внутри блока. И с ней уже не будет граблей. Это не жс, где ради этого надо целую функцию городить.
З.Ы. Именно поэтому я против захвата по ссылке.
https://ideone.com/muioFb
Для foreach починили, для for забили.
По мне вышло ещё хуже чем если бы не чинили.
> а тут так не прокатило
В обосраном ранее «JavaScript» let работает однообразно, вне зависимости от типа цикла.
И var тоже работает однообразно.
Кстати, «Борманд» участвовал в этом обсуждении, но это настолько нелогичная вещь (в смысле, что поведение из слов «let» и «var» ну никак не выводится), что не запомнилась:
https://govnokod.ru/26280#comment518157
Просто Let локален для скоупа, при заходе в { } каждый раз это новая переменная.
Разницу между var и let наглядно иллюстрирует такой пример:
У Var остаётся прежний адрес.
А Let при заходе в скоуп каждый раз инициализируется новой переменной по новому адресу.
По этой причине замыкание хватает каждый раз новую ссылку. Но это именно ссылка.
Со всеми вытекающими проблемами.
Обосраться с let не просто легко, а ОЧЕНЬ легко
3 3 3
Т.к. let в верхнем скоупе, то это все три итерации одна и та же переменная.
А захват идёт по её ссылке.
Именно поэтому я за «PHP».
И как назло, for(let i будет в самом простом случае, когда и баг легко исправить.
А когда случай будет менее тривиальным, летонядь обосрётся:
Варвары с первых дней чтения мануалов узнавали про багор с циклами, заучивали конструкцию
и больше никогда у них ничего неправильного в функции не попалало.
Зумеры-летоняди всегда пользовались летом, про багры не знают и не готовы, что лет готов их подвести в любой момент.
Летоняди соснули. Бамп отсосу летонядей.
Никто никогда так не будет писать, все напишут один цикл и if внутри
У тех, кто пишет код, все три примера встречались в каком-либо виде.
ты можешь приводить хоть 20 таких же примеров и говорить что у тех кто пишет код регулярно возникают раздербанные циклы с произвольным вызовом setTimeout но это не так о чем я и говорю когда называю твои примеры не реальными
Превет братик харашо пишеш
> регулярно возникают раздербанные циклы с произвольным вызовом setTimeout но это не так
Это почти так. Разумеется, не setTimeout, а какой-нибудь коллбек. Например, обход JSON, генерация контролов и обработчиков событий.
Да, не в каждом цикле, но временами встречается.
Вероятнее всего сперва напишут for (let i ...
А потом поменяется логика и for придётся заменить на цикл с постусловием.
Обезьянка без задней мысли поменяет и даже не поймёт что она обосралась.
И вот ради этой зумерской хрюкни мне ещё предлагают попердолиться с Babel, я правильно понимаю?
Цикл с переменной аккумулятором крайне распространённый паттерн.
В «Си» нет никаких «замыканий». Именно поэтому я за «Си».
Делают callback и передают ему какой-нить void* вручную захватывая что нужно?
Или в мире клиентухов это так же нинужно, как и циклы с постусловиями?
в мире клиентухов вся эта дрисня вхуй не сдалась
но это не повод мне дристать под себя
Var хоистится а let нет
Думаю можно.
> Ну или изнутри лямбды нельзя, даже если её прям сразу позвать.
Полагаю там условный класс, в котором локальная копия i устанавливается при конструировании на каждой итерации.
Псевдокод:
А в var там внутри ref i;
Но, повторюсь, как по мне все проблемы от того что программирующего заставляют смешивать образы императивного и функционального.
Если писать в одном, функциональном стиле, проблем по-просту не возникает
> Ну или изнутри лямбды нельзя, даже если её прям сразу позвать. Одно из двух.
Оказывается можно
Пример 1024-- когда мутация захваченной питушни меняет ф-цию.
То есть реализация там чуть сложнее чем я писал выше.
Выходит и var, и let оба захватывают по ссылке.
Только вот let не позволяет redefinition в скоупе.
И на каждой итерации генерится ссылка на новую переменную.
Почему не сделать так, шоп программист явно выбирал что и как захватывать?
I’m reminded of the artist who worked here years ago who used an early version of 3D Studio. Asked for a quote by Autodesk for use in marketing materials, he replied, “It’s like having ILM in a box!” Needless to say, his employment here didn’t last long