Си диез / Говнокод #27628 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 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();
}

По мотивам https://govnokod.ru/11946

Просто форкнул и запустил старый пример LispGovno (мир ему)

Старый пример: https://ideone.com/RaiHr

Новый пример: https://ideone.com/M1ducs

Однако получил совершенно другой результат.

Запостил: 3.14159265 3.14159265, (Updated )

Комментарии (182) RSS

    • Перевёл.

      https://ideone.com/Y0YAKW

      Но тут нужно учитывать что в «Йажа» питузы учёные, ходят к электричеству подключенные.

      Учились на шишках C# и сделали всё, чтобы не обосраться.

      И неявный final на захватываемых переменных. И даже с var, несмотря на мутацию компилируется и работает очевидным образом.
      import java.util.*;
      import java.lang.*;
      import java.io.*;
      
      class Ideone
      {
      	public static void main (String[] args) throws java.lang.Exception
      	{
      		var actions = new ArrayList<Runnable>();
      		
      		for(var i : Arrays.asList(1,2,3))
      		{
      		    actions.add(() -> System.out.println(i));
      		}
      		
      		for (var action : actions)
      		{
      		    action.run();
      		}		
      		
      	}
      }
      Ответить
  • Как нам любят рассказывать сектанты JVM/CLR.

    Сишка плохая. В Сишке нет переносимости программ, код на разных платформах и компиляторах работает по-разному. UB там.

    А вот в managed environment, где код исполняется виртуальной машиной такой проблемы нет. Всё однообразно и предсказуемо.

    «Write once — run everywhere».

    Но у нас все ходы записаны в ideone. И маркетинговая методичка сектантов — просто bullshit.
    Ответить
        • LLVM - это лоу левел виртуал машин... но я тебя уверяю - ничего общего с виртуальной машиной тут нет. такэе как и JVM и CLR. которые "окружение для выполнение кода" но никак не виртуальная машина 🙂
          Ответить
            • Это машина в компьютерной игре «Minecraft» из поршней, красного камня и блоков слизи.
              Ответить
                • > дно мира

                  В «Minetest», опенсурсном воксельном движке, для которого ТОРТ выучил «Lua», дно мира находится на 30_912 метров ниже уровня моря, это пиздец как долго надо туда копать: если один блок ломается за секунду, то «бурение» до самых недр майнтеста займёт около восьми с половиной часов!
                  Ответить
          • > никак не виртуальная машина

            Ну вообще говоря спека LLVM описывает поведение какой-то абстрактной машины, которая не существует в реальности. А раз не существует -- значит виртуальная.

            То что потом это поведение пытаются воспроизвести на реальной машине, сгенерив похожий по смыслу код, сути не меняет.
            Ответить
            • Все компьютеры это виртуальные машины, основанные на какой-то там машине тьюринга.
              Ответить
            • > которая не существует в реальности

              А что если и реальности на самом-то деле не существует? Может это все мой сон, и тогда все машины - виртуальные.
              Ответить
              • Раз это твой сон, сделай так, чтобы Полимер Скипидар разбанил моего опсоса, а то с мобилы debug mode off. Или чтобы забанил ещё и comhem.
                Ответить
                • Я пока не до конца контролирую свой сон. Но наши отделы работают над этим
                  Ответить
                  • А ещё добавь в бэклог, пожалуйста, чтобы у меня в велосипеде тормозуха сама поменялась, а то лень тащиться в магазин за новой. Я подожду.
                    Ответить
                    • Вообще-то я достаточно много занимался осознанными снами, и там далеко не всегда получалось творить всякую дичь, даже если ты 100% уверен что это сон, и осознал это. У меня например была такая фигня, что я понял что это я в сне, захотел проснуться, но нифига не вышло, да и всякие приколы с проламыванием стен не работали, и тогда я махнул на это дело и начал там всякую фигню исследовать.

                      Кстати там еще в том сне Volkov Commander (или Norton Commander? Но я почему-то про Volkov подумал) какой-то был на старом IBM-совместимом ПК. Вот то точно виртуальная машина.
                      Ответить
                            • Если ты про Lure Of Chaos то нет. И какое он к этому имеет отношение, что вдруг возникло подозрение, что я его файка?
                              Ответить
                                • > Ну, у него безымянный на юзерпике.

                                  В "Planescape: Torment" я не играл, хотя и читал примерно, о чем там сюжет. Мне сейчас уже слишком лень читать столько текста и столько диалогов прокликивать.

                                  Вот в "Arcanum" я например играл, там можно было на помойке из мусорок доставать ботинки и потом их продавать. А еще крафтить линолеумный вентилятор всякую хуйню из запчастей с мусорки.
                                  Ответить
                                      • Инстед много чего умеет, и звуки, и картинки, и pnc, и даже жанры за пределами квестов. Для чисто текстовых можно и попроще взять что-то.

                                        Другое дело, что текстовые квесты не нужны
                                        Ответить
                                    • А мне нравилось читать тексты в некоторых квестах
                                      Loom, SpaceQuest, вот это всё

                                      Хотя во многих играх они и правда унылое пафосное г-но, как будто посмотрел Mockbuster
                                      Ответить
    • > нет переносимости программ, код на разных платформах и компиляторах работает по-разному
      > где код исполняется виртуальной машиной такой проблемы нет

      Переносимость. Когда ваш жабий байткод будет запускаться на питонячей VM, с чем, по вашим словам, проблем не должно быть, тогда и приходите.
      Ответить
  • Компилятор из .NET 4.6 для C# 5:
    1
    2
    3


    Компилятор из «Mono» вернул такой же результат.

    .NET 2.0 не смог найти «Linq».

    Компилятор из .NET 3.5 возвращает другой результат:
    3
    3
    3


    Итого: .NET 3.5 с четвёркой вообще несовместим.
    Ответить
    • Спасибо.

      jsников любят обсирать за var.

      Однако даже у ненавидимых всеми скриптухов хватило ума чтобы не ломать устойчивое поведение, не порождать Undefined Behavior.

      А просто ввести новый кейворд let.
      Ответить
      • Не знаю. Я стандартов по C# не читал (кстати, они есть: «Микрософту» удалось его протащить в ECMA и в ISO).

        Надо ещё в новомодном «.Net Core» проверить.

        «Portable.Net»/«dotGNU» сгнил, не дожив до новых версий платформы.

        Какие ещё есть реализации?
        Ответить
          • Кстати, в «Microsoft.NET» два компилятора для «C#»: «Roslyn» и классический. У них могут быть расхождения в интерпретации некоторых синтаксиальных психоз.
            Ответить
            • моя мечта детства была что если Roslyn написали на C# что бы компилировать C# ... то я мечтал написать cs2cpp которая сгенерит C++ для компиляции Roslyn в нативе 🙂
              Ответить
      • Посмотрел дизасм выхлопа компилятора из 3.5 и 4.6. Разница в несколько инструкций. Фрагмент из 3.5:
         
            ldnull
            stloc.1
            newobj   instance void <>c__DisplayClass2::.ctor()
            stloc.2
            br.s     loc_59
        loc_30:					// CODE	XREF: Main+54j

        Фрагмент из 4.6:
         
            br.s     loc_59
        loc_28:					// CODE	XREF: Main+54j
            ldnull
            stloc.1
            newobj   instance void <>c__DisplayClass2::.ctor()
            stloc.2

        Порядок нескольких действий изменился. Надо будет разобраться, как он цикл организовал, тогда станет ясно, почему такие результаты.

        Вроде в 3.5 конструктор вызывается до цикла (поэтому три копии одного результата), а в 4.x конструктор вызывается в цикле (поэтому результаты разные).
        Ответить
          • А этот исходник компилятором из 3.5 и из 4.x компилируется в один и тот же байткод (разница только в требуемой версии в заголовке).
            Ответить
            • Так а что же они починили?

              Багор ведь остался. Лаже не надо класс со ссылкой городить.
              for(var i = 0; i<3; i++)
              {
                  actions.add(() -> System.out.println(i));
              }
              
              for (var action : actions)
              {
                  action.run();
              }

              То есть теперь (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

              Пиздец. Просто пиздец.
              Ответить
              • В «Лажа» кстати подобный цикл компилироваться не хочет.

                Она просекает что мутабельный питух хочет пролезть в замыкание и не даёт ему этого сделать.
                for(var i = 0; i<3; i++)
                {
                    actions.add(() -> System.out.println(i));
                }
                Main.java:13: error: local variables referenced from a lambda expression must be final or effectively final
                		    actions.add(() -> System.out.println(i));
                		                                         ^
                1 error
                https://ideone.com/Tz5Ad1

                То есть в «Йажа» допустима педерача сложного объекта по ссылке (массив, объект), но явно видно что это ссылка.

                А мутация захватываемого питуха просто запрещена.
                Ответить
  • С другой стороны, если срать очень хочется, то можно ненароком и обсраться.
    public static void main (String[] args) throws java.lang.Exception
    {
    	var actions = new ArrayList<Runnable>();
    	
    	for(var i = new int[]{0};i[0]<3;i[0]++)
    	{
    	    actions.add(() -> System.out.println(i[0]));
    	}
    	
    	for (var action : actions)
    	{
    	    action.run();
    	}
    }

    «Йажа» конечно делали питузы учёные, а мы им массивы мучёные.

    https://ideone.com/rGrzw3
    Success	#stdin #stdout 0.07s 47992KB
    
    3
    3
    3
    Ответить
  • Так а что они починили? Ради чего поломали совместимость?
    Чтобы анскильным отбросам было проще жить?

    Аналогично C#
    https://ideone.com/LlUtqP
    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    public class Test
    {
    	class Bagor {
    		public int i=0;
    		public static Bagor operator ++(Bagor a)
    		{
    		    a.i += 1;
    		    return a;
    		}		
    		public override string ToString()
    		{
    		    return "" + i;
    		}		
    	}
    	
    	public static void Main()
    	{
    		var actions = new List<Action>();
    		
    		for (var it = new Bagor(); it.i<3; it++ )
    		{
    		    actions.Add(() => Console.WriteLine(it));
    		}
    		 
    		foreach (var action in actions)
    		{
    		    action();
    		}
    	}
    }
    
    Success	#stdin #stdout 0.02s 24480KB
    3
    3
    3
    Ответить
  • Прогнал через декомпилятор C#.

    Программа, собранная компилятором из .NET 3.5:
     
            public static void Main() {
                bool flag;
    
                List<Action> list = new List<Action>();
                IEnumerator<int> ienumerator = Enumerable.Range(1, 3).GetEnumerator();
                try {
                    Action action1 = null;
                    Test.<>c__DisplayClass2 <>c__DisplayClass2 = new Test.<>c__DisplayClass2();
                    while (flag) {
                        <>c__DisplayClass2.i = ienumerator.get_Current();
                        if (action1 == null) action1 = new Action(<>c__DisplayClass2.<Main>b__0);
                        list.Add(action1);
                        flag = ienumerator.MoveNext();
                    }
                } finally {
                    flag = ienumerator == null;
                    if (!flag) ienumerator.Dispose();
                }
                List<Action>.Enumerator enumerator = list.GetEnumerator();
                try {
                    while (flag) {
                        Action action2 = enumerator.get_Current();
                        action2.Invoke();
                        flag = enumerator.MoveNext();
                    }
                } finally {
                    enumerator.Dispose();
                }
            }
    Ответить
    • Программа, собранная компилятором из .NET 4.x:
       
              public static void Main() {
                  bool flag;
      
                  List<Action> list = new List<Action>();
                  IEnumerator<int> ienumerator = Enumerable.Range(1, 3).GetEnumerator();
                  try {
                      while (flag) {
                          Action action1 = null;
                          Test.<>c__DisplayClass2 <>c__DisplayClass2 = new Test.<>c__DisplayClass2();
                          <>c__DisplayClass2.i = ienumerator.get_Current();
                          if (action1 == null) action1 = new Action(<>c__DisplayClass2, <>c__DisplayClass2.<Main>b__0);
                          list.Add(action1);
                          flag = ienumerator.MoveNext();
                      }
                  } finally {
                      flag = ienumerator == null;
                      if (!flag) ienumerator.Dispose();
                  }
                  List<Action>.Enumerator enumerator = list.GetEnumerator();
                  try {
                      while (flag) {
                          Action action2 = enumerator.get_Current();
                          action2.Invoke();
                          flag = enumerator.MoveNext();
                      }
                  } finally {
                      enumerator.Dispose();
                  }
              }
      Ответить
      • diff:
         
                     List<Action> list = new List<Action>();
                     IEnumerator<int> ienumerator = Enumerable.Range(1, 3).GetEnumerator();
                     try {
        -                Action action1 = null;
        -                Test.<>c__DisplayClass2 <>c__DisplayClass2 = new Test.<>c__DisplayClass2();
                         while (flag) {
        +                    Action action1 = null;
        +                    Test.<>c__DisplayClass2 <>c__DisplayClass2 = new Test.<>c__DisplayClass2();
                             <>c__DisplayClass2.i = ienumerator.get_Current();
        -                    if (action1 == null) action1 = new Action(<>c__DisplayClass2.<Main>b__0);
        +                    if (action1 == null) action1 = new Action(<>c__DisplayClass2, <>c__DisplayClass2.<Main>b__0);
                             list.Add(action1);
                             flag = ienumerator.MoveNext();
                         }
        Ответить
        • В первом случае (3.5) оно создает один объект перед циклом и трижды закидывает один и тот же объект в список.
          По ходу дела мутируя его. Логика как в этом примере: https://govnokod.ru/27628#comment666384 у меня тоже один объект Bagor.

          Test.<>c__DisplayClass2 <>c__DisplayClass2 = new Test.<>c__DisplayClass2();

          Во-втором случае это три разных объекта. На каждой итерации создаётся уникальный питух.
          Ответить
          • Как всё сложно. Такой маленький код генерирует какие-то try...finally, какие-то action1, action2, какие-то флаги. Именно поэтому я за «PHP»:

            <?php
            $actions = [];
            foreach (range(1, 3) as $i)
            {
                $actions[] = function()use($i){echo $i, PHP_EOL;};
            }
            
            foreach ($actions as $action)
            {
                $action();
            }


            Возвращает 1 2 3:
            https://ideone.com/2TDMMb

            В «PHP» мы явно указываем, как захватывать $i: по ссылке или по значению. Я захватил по значению.
            Ответить
              • Кр-р-расота. Раньше мы уже оценили годность use, в плане избирательного захвата.

                И никакой тебе пирдоли, неопределённых поведений.

                Вот что значит язык для белых людей.
                Ответить
                • В PHP8 поднасрали: ввели стрелочные функции, как в новом JS. Вот там много неочевидного. Но я восьмёрку ещё не тестировал.
                  Ответить
                    • Нет, «ротоёб» писал про другие стрелки: он писал про получение свойств объектов. Как я понимаю, он за «ассоциативные массивы».
                      Ответить
                      • my bad.

                        Джавашки меня смутили со своим ->
                        У C#, PHP, JS замыкание =>

                        > он писал про получение свойств объектов
                        Это как в Сишке доступ к полю указателя?
                        Ответить
                        • И правда. Напридумывают несовместимых обозначений.

                          Это как {} в «Паскале» означает комментарий, а в языках с сиподобным синтаксисом — блок.

                          > Это как в Сишке доступ к полю указателя?

                          Ну да, скосплеили ->, только в «PHP» явно разыменовывать ничего не нужно, потому что тут везде сахар для ссылок.
                          Ответить
                • > Раньше мы уже оценили годность use, в плане избирательного захвата.

                  Кроме крестов и «PHP», ещё где-нибудь контекст для захвата указывается явно?
                  Ответить
        • Я не знаю, кто все эти классы, но у меня такое ощущение, что 3.5 создавал один экземпляр замыкания и в нём подкручивал i, поэтому на выходе из цикла получалось, что i = 3 для всех элементов.
          Ответить
      • > Такой маленький код генерирует какие-то try...finally, какие-то action1, action2, какие-то флаги.

        IEnumerator может быть не только детерминированный Range(1, 3), а и внешние вызовы ололо-linq, которое например лезет в базу или получает по http.

        А т.к. RAII нет, то generic реализация макроса всегда делает его Dispose. По принципу: «абы чего не вышло».

        foreach тоже синтаксический сахар, который внутри себя вызывает обычный итератор.

        C одной стороны MS конечно молодцы, что оперируя препроцессором, быстро нагородили в языке синтаксического сахарку не меняя существующего бат-кода.
        Этот же подход мы видели в «TypeScript», когда из пары строк генерятся сотни строк вореционной JS-дрисни.
        https://govnokod.ru/27615#comment661036

        С другой странно что сишников ругают за препроцессорный подход. Хотя они по сути делают абсолютно ТО ЖЕ САМОЕ,

        Думаю совещание в Редмонде по новым фичам C# выглядело примерно так:

        Смотри, джависты, они тебе расширяться мешают.
        А я вот, давай я здесь насру, и джависты все прилетят сюда, и мы их наймём, слышишь?
        И тебе тогда спать, ой, спать будет хорошо. Давай? Я насру функционалом, а джависты все прилетят, сюда, к нам.
        Ну, куда им ещё, ихнее место-то тока здесь, и… ооой… хочешь, я насру здесь?И джависты, и мы их наймём! Ну что, срать?
        Ответить
        • Шарпеи и ТСеры наверное в 99% случаев могут позволить себе вообще не читать выхлоп компилятора

          Просто у них есть сырцы и какие-то, грубо говря, символы для дебага, и всё
          не?
          Ответить
          • > вообще не читать выхлоп компилятора

            Это не выхлоп компилятора.

            Это раскрытие синтаксического сахара препроцессором а-ля Сишка.

            В одном случае оно из одного «TypeScript» кода (с классами, типами форычами и елдаками) генерит «JavaScript», который тоже валидный «TypeScript» код.

            В случае .NET оно из одного C# кода (с форычами и лямбдами) генерит другой, тоже валидный C#-код.

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

            По сути это ничем не отличается от макросов (местами жутких), которые пишет j123123.

            Они тоже раскрывают няшные макросы на Сишке в чудовищные пиздецы на той же самой Сишке.

            Только в случае C# и TS такие макросы из коробки встроены в язык. И написать свои нельзя.
            Ответить
            • Ну выхлоп препроцессора, какая разница?
              Зачем мне знать что он выхлпнул?

              Это как магнленные имена в С++ читать.

              Макросы j1234 ужасны не выхлопом, а своим кодом. Если его не читать, то он ок.

              Я уверен, что использовал в сишке ужасные макросы, и даже не знал, что пиша `Foo()`` я использую на самом деле ужасный макрос
              Ответить
              • > Ну выхлоп препроцессора, какая разница?
                > Зачем мне знать что он выхлпнул?

                Пока абстракция работает думаю незачем.

                Но только она начинает подтекать и вести себя непредсказуемо, как в нашем случае.

                Тогда всё-равно приходится лезть в кишки и смотреть весь этот неявный ужас.

                Чтобы понять как она работает, и использовать её без багров.
                Ответить
                • А если бы для этого говна завезли волшебные опкоды, и это не препроцессор бы транспилировал, а компилятор компилировал, то было бы лучше?
                  Ответить
                  • > если бы для этого говна завезли волшебные опкоды,
                    > и это не препроцессор бы транспилировал, а компилятор компилировал, то было бы лучше?

                    Для пирформанса возможно и лучше.

                    В «Йажа» foreach по списку до сих пор в несколько раз медленее анскильных импераций :
                    for (int i=0;i<list.size();i++)
                    В C# как мы видим тоже самое.
                    foreach раскрывается в унылый питератор, а не супербыстрый опкод обхода с минимальной перепитушнёй.

                    Хотя наоборот эти циклы должны быть супероптимизированы.

                    Т.к. кишки явной индексации спрятаны от пользователя и можно применять целый набор оптимизаций: обходить массив оптимальном направлении, убирать array bounds checks без пирдолинга с доказательствами, итд.
                    Ответить
                    • Страшно даже преставить как сосёт котлиновский
                      petuhi.forEach { println(it) }

                      по сравнению с сишкообразным фором на йаже
                      Ответить
                    • А почему нельзя foreach раскрыть в обычный for i?
                      Ответить
                      • Матапушто он работает с итератором, а не только с индесируемым массивом ежей?
                        Ответить
                        • Анскильный компилятор не может определить, что там массив?
                          Ответить
                          • Ну у яжи вообще довольно анксильный компилятор, это правда

                            Джит умный, а джавак -- нет

                            Альзо, если там List а не массив, то компилятор и не знает заранее, там же интерфес
                            Ответить
                            • Это правда. Подозреваю, что «forEach» в ко-ко — это extension method для интерфейса Iterable (или как он там), поэтому компилятор отсасывает.
                              Код:
                              fun foo(lst: List<Int>) {
                                  lst.forEach(::println)
                              }
                              
                              fun main(args: Array<String>) {
                                  val lst = listOf(1, 2, 3, 4, 5)
                                  foo(lst)
                              }

                              Байткод (только foo()):
                              00000000 : aload_0
                              00000001 : ldc                 "lst"
                              00000003 : invokestatic        void kotlin.jvm.internal.Intrinsics.checkNotNullParameter(java.lang.Object, java.lang.String)
                              00000006 : aload_0
                              00000007 : checkcast           java.lang.Iterable
                              0000000A : astore_1
                              0000000B : iconst_0
                              0000000C : istore_2
                              0000000D : aload_1
                              0000000E : invokeinterface     java.util.Iterator java.lang.Iterable.iterator(), 1
                              00000013 : astore_3
                              00000014 : aload_3
                              00000015 : invokeinterface     boolean java.util.Iterator.hasNext(), 1
                              0000001A : ifeq                pos.00000040
                              0000001D : aload_3
                              0000001E : invokeinterface     java.lang.Object java.util.Iterator.next(), 1
                              00000023 : astore              local.04
                              00000025 : aload               local.04
                              00000027 : checkcast           java.lang.Number
                              0000002A : invokevirtual       int java.lang.Number.intValue()
                              0000002D : istore              local.05
                              0000002F : iconst_0
                              00000030 : istore              local.06
                              00000032 : iconst_0
                              00000033 : istore              local.07
                              00000035 : getstatic           java.io.PrintStream java.lang.System.out
                              00000038 : iload               local.05
                              0000003A : invokevirtual       void java.io.PrintStream.println(int)
                              0000003D : goto                pos.00000014
                              00000040 : nop
                              00000041 : return

                              forEach() развернулся в 00000014—0000003D.
                              Ответить
                              • Царь лопннул бы от смеха, расскажи мы ему как в кокойаже итерация по массиву интов (семантически) превратилася в получение указателя вызовом метода next() с последующим разыменовыванием
                                Ответить
                                • Там ещё и ебанутый hasNext() приделан, не говоря уже про checkcast на 0027.

                                  Даже в «Питоне» осилили итераторы без двойной работы, а в ЙАЖЕ до сих пор на каждой итерации дублируют логику в next() и hasNext().
                                  Ответить
                                  • >Даже в «Питоне» осилили итераторы без двойной работы

                                    за счет исключения

                                    в яже было бы еще хужее
                                    Ответить
                                    • Да. Штука в том, что в «Питоне» исключения фактически бесплатны.
                                      А вот классические ЙАЖАвские итераторы выглядят примерно так:
                                      public Boolean hasNext() { if (...) return ... }
                                      public T next() { if (hasNext()) { return getNext(); } else { throw new IndexOutOfBoundError(); } }

                                      Как результат — условие в hasNext() проверяется джва раза на каждой итерации. И умного оптимизирующего компилятора (вроде сишного или крестового), который бы это определил и вырезал лишние проверки, в ЙАЖУ не завезли. Пиздец.
                                      Ответить
                                  • checkcast это копеечная хуйня.

                                    > invokevirtual int java.lang.Number.intValue()
                                    А вот автоанбоксинг виртуальным методом (опять на суперклассе с 10ю наследниками: Long, Byte, Integer, Float, Double, итд) это прощай пирформанс.
                                    Ответить
                                • > Царь лопннул бы от смеха, расскажи мы ему как в кокойаже итерация по массиву интов (семантически) превратилася в получение указателя вызовом метода next()

                                  Причём два ВИРТУАЛЬНЫХ вывоза: 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 несколько сотен.
                                  Ответить
                                  • Мы как-то там ковырялись, и наковыряли такую козюлю, что джава делала invokevirtual при вызове приватного метода в final классе:)

                                    Но может с тех пор что-то улучшилось.

                                    Хорошо, что в крестах вся эта питушня с итераторами работает без виртуальных таблиц
                                    Ответить
                              • С другой стороны, распирдоливать лямбды он вполне умеет:
                                fun foo(lst: List<Int>) {
                                    lst.forEach { println(it) }
                                }

                                00000000 : aload_0
                                00000001 : ldc                 "lst"
                                00000003 : invokestatic        void kotlin.jvm.internal.Intrinsics.checkNotNullParameter(java.lang.Object, java.lang.String)
                                00000006 : aload_0
                                00000007 : checkcast           java.lang.Iterable
                                0000000A : astore_1
                                0000000B : iconst_0
                                0000000C : istore_2
                                0000000D : aload_1
                                0000000E : invokeinterface     java.util.Iterator java.lang.Iterable.iterator(), 1
                                00000013 : astore_3
                                00000014 : aload_3
                                00000015 : invokeinterface     boolean java.util.Iterator.hasNext(), 1
                                0000001A : ifeq                pos.00000041
                                0000001D : aload_3
                                0000001E : invokeinterface     java.lang.Object java.util.Iterator.next(), 1
                                00000023 : astore              local.04
                                00000025 : aload               local.04
                                00000027 : checkcast           java.lang.Number
                                0000002A : invokevirtual       int java.lang.Number.intValue()
                                0000002D : istore              local.05
                                0000002F : iconst_0
                                00000030 : istore              local.06
                                00000032 : iconst_0
                                00000033 : istore              local.07
                                00000035 : getstatic           java.io.PrintStream java.lang.System.out
                                00000038 : iload               local.05
                                0000003A : invokevirtual       void java.io.PrintStream.println(int)
                                0000003D : nop
                                0000003E : goto                pos.00000014
                                00000041 : nop
                                00000042 : return

                                Только на 0000003D лишний nop добавился.
                                Ответить
                            • > Альзо, если там List а не массив, то компилятор и не знает заранее, там же интерфес

                              Неправда. Зачастую знает.
                              Но даже один раз сделать instanceof RandomAccess перед циклом будет быстрее чем плодить лишний объект и каждый раз дрочить hasNext().

                              instanceof is very cheap.
                              Ответить
                              • Ого, и правда!
                                fun foo(lst: Array<Int>) {
                                    lst.forEach { println(it) }
                                }

                                Результат:
                                00000000 : aload_0
                                00000001 : ldc                 "lst"
                                00000003 : invokestatic        void kotlin.jvm.internal.Intrinsics.checkNotNullParameter(java.lang.Object, java.lang.String)
                                00000006 : aload_0
                                00000007 : astore_1
                                00000008 : iconst_0
                                00000009 : istore_2
                                0000000A : aload_1
                                0000000B : astore_3
                                0000000C : aload_3
                                0000000D : arraylength
                                0000000E : istore              local.04
                                00000010 : iconst_0
                                00000011 : istore              local.05
                                00000013 : iload               local.05
                                00000015 : iload               local.04
                                00000017 : if_icmpge           pos.0000003F
                                0000001A : aload_3
                                0000001B : iload               local.05
                                0000001D : aaload
                                0000001E : astore              local.06
                                00000020 : aload               local.06
                                00000022 : checkcast           java.lang.Number
                                00000025 : invokevirtual       int java.lang.Number.intValue()
                                00000028 : istore              local.07
                                0000002A : iconst_0
                                0000002B : istore              local.08
                                0000002D : iconst_0
                                0000002E : istore              local.09
                                00000030 : getstatic           java.io.PrintStream java.lang.System.out
                                00000033 : iload               local.07
                                00000035 : invokevirtual       void java.io.PrintStream.println(int)
                                00000038 : nop
                                00000039 : iinc                local.05, 1
                                0000003C : goto                pos.00000013
                                0000003F : nop
                                00000040 : return

                                Так нормально проходит по underlying массиву через «aaload».
                                Ответить
                                • Cotlin — это надстройка на Jawa, как говно обмазанное мёдом.
                                  Ответить
                                • Это же Array, я даже не уверен, что он Iterable

                                  А мы про лист
                                  Ответить
                                    • Гост, ты мну не понял:)

                                      Смотри:
                                      Есть интерфейс `java.lang.Iterable`

                                      Его наследники ArrayList, LinkedList, Set, еще какая-то дрисня, и код может его получать и вообще не знать что у тебя там ArrayList (то есть массив по сути) а не LinkedList.

                                      А Array его не наследует ни в джове, ни в котлине

                                      Потому универасальный код не написать, и потому
                                      `Array.forEach` это ЯВНО массив, и его можно оптимизнуть
                                      Ответить
                                • Пацаны, а можете так же с лишпа покровы посрывать?
                                  Ответить
                              • Если лист то знает, а есть там итерабл?

                                про рендом аксесс согласен

                                Вообще мне тут больше нравится то, что сделали крестобляди

                                У них есть много сортов интераторов с разными свойствами, и можно в функции явно написать "суй суда итератор с рендом аксессом" и туда лист не всунется просто
                                Ответить
                                • Просто интересно сможет ли питух скомпилить что-то приличное, если ему в форыч инстанс RandomAccess подсунуть.
                                  Class ArrayList<E>
                                      java.lang.Object
                                          java.util.AbstractCollection<E>
                                              java.util.AbstractList<E>
                                                  java.util.ArrayList<E> 
                                  
                                      All Implemented Interfaces:
                                          Serializable, Cloneable, Iterable<E>, Collection<E>, List<E>, RandomAccess
                                  Ответить
                                  • Я боюсь, что питух не догадатется< что он RandomAccess а увидит Iterable и пойдет по известной дорожке((

                                    ну ща гост проверит
                                    Ответить
                                    • Я забыл, что Array в коко — это сахарок над [].
                                      fun foo(lst: ArrayList<Int>) {
                                          lst.forEach { println(it) }
                                      }
                                      
                                      fun main(args: Array<String>) {
                                          val lst = arrayListOf(1, 2, 3, 4, 5)
                                          foo(lst)
                                      }


                                      00000000 : aload_0
                                      00000001 : ldc                 "lst"
                                      00000003 : invokestatic        void kotlin.jvm.internal.Intrinsics.checkNotNullParameter(java.lang.Object, java.lang.String)
                                      00000006 : aload_0
                                      00000007 : checkcast           java.lang.Iterable
                                      0000000A : astore_1
                                      0000000B : iconst_0
                                      0000000C : istore_2
                                      0000000D : aload_1
                                      0000000E : invokeinterface     java.util.Iterator java.lang.Iterable.iterator(), 1
                                      00000013 : astore_3
                                      00000014 : aload_3
                                      00000015 : invokeinterface     boolean java.util.Iterator.hasNext(), 1
                                      0000001A : ifeq                pos.00000041
                                      0000001D : aload_3
                                      0000001E : invokeinterface     java.lang.Object java.util.Iterator.next(), 1
                                      00000023 : astore              local.04
                                      00000025 : aload               local.04
                                      00000027 : checkcast           java.lang.Number
                                      0000002A : invokevirtual       int java.lang.Number.intValue()
                                      0000002D : istore              local.05
                                      0000002F : iconst_0
                                      00000030 : istore              local.06
                                      00000032 : iconst_0
                                      00000033 : istore              local.07
                                      00000035 : getstatic           java.io.PrintStream java.lang.System.out
                                      00000038 : iload               local.05
                                      0000003A : invokevirtual       void java.io.PrintStream.println(int)
                                      0000003D : nop
                                      0000003E : goto                pos.00000014
                                      00000041 : nop
                                      00000042 : return

                                      Соснул.

                                      А если сделать Ctrl+LMB по «forEach», то ожидаемо придём в _Collections.kt и увидим extension-метод:
                                      @kotlin.internal.HidesMembers
                                      public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {
                                          for (element in this) action(element)
                                      }

                                      UPD: не тот метод скопипастил.
                                      Ответить
                                      • > Соснул.

                                        И тут мы приходим к тому, о чём я уже говорил.

                                        Йажа-сектант это в 95% мразь, а в 5% просто обманутый/неразобравшийся человек.

                                        Они не сделали быстрый форыч.

                                        Они просто обмазали сахарком унылый питератор.

                                        И в этом и заключается фокус.

                                        > checkIndexOverflow(index++)
                                        Блять. БЛЯТЬ. Две проверки мало. Нужно сделать ТРИ!
                                        Ответить
                                      • Да, сахарок

                                        Ему ведь надо быть совместимым с яжей


                                        А array ([]) в яжа это не часть Collections
                                        Ответить
                                        • > Ему ведь надо быть совместимым с яжей

                                          Йажа тоже не генерит оптимальный байт-код, который чекает что это RandomAccess.
                                          И тоже неспособна сделать нормальный for без итератора.

                                          То есть обосрались, since 1.4 предлагая на каждый обход списка для оптимальности делать два цикла и instanceof RandomAccess руками.
                                          Ответить
                          • Кстати знаю язык, где для итерации по массиву ОБЫЧНО используют лямбду-кложу, которая вызывается на каждый элемент

                            Угадайте язык и почему так
                            Ответить
                          • > Анскильный компилятор не может определить, что там массив?

                            Так точно.

                            Хотя в компайл тайме информации об этом достаточно.
                            public interface RandomAccess
                            
                            Marker interface used by List implementations to indicate that they support 
                            fast (generally constant time) random access. 
                            The primary purpose of this interface is to allow generic algorithms to alter their behavior
                            to provide good performance when applied to either random or sequential access lists.
                            
                            The best algorithms for manipulating random access lists (such as ArrayList) 
                            can produce quadratic behavior when applied to sequential access lists (such as LinkedList). 
                            Generic list algorithms are encouraged to check whether the given list is an instanceof
                            this interface before applying an algorithm that would provide poor performance if it were applied to a sequential access list, and to alter their behavior if necessary to guarantee acceptable performance.
                            
                            It is recognized that the distinction between random and sequential access is often fuzzy.
                            For example, some List implementations provide asymptotically linear access times if they get huge, but constant access times in practice.
                            Such a List implementation should generally implement this interface. 
                            
                            As a rule of thumb, a List implementation should implement this interface if, for typical instances of the class, this loop:
                            
                                 for (int i=0, n=list.size(); i < n; i++)
                                     list.get(i);
                             
                            
                            runs faster than this loop:
                            
                                 for (Iterator i=list.iterator(); i.hasNext(); )
                                     i.next();
                            
                            Since:   1.4

                            https://docs.oracle.com/javase/7/docs/api/java/util/RandomAccess.html
                            Со времён 1.4 всё известно. Извинити, руки из жопы, вот вам ещё тонна синтаксической сахарозы.
                            Ответить
                            • > runs faster than this loop

                              Какой багор )))

                              Оптимизатор не замечает, что там в итераторе тупо циферка, которая инкрементится? Тут вроде даже не надо магических интерфейсов, банальный инлайн свернёт второй цикл к первому.
                              Ответить
                              • > банальный инлайн свернёт второй цикл к первому

                                А как же его заинлайнить, если приходит List непонятно какого типа, а next/hasNext виртуальные методы в интерфейсе Iterator?

                                Нет уж, батенька извольте invokeinterface с таблицей вирутальных функций. Всё как полагается.

                                https://govnokod.ru/27628#comment666723
                                Ответить
                                • > непонятно какого типа

                                  Ну я так понимаю, он не заинлайнит и если тип понятный и описан строчкой выше?
                                  Ответить
                                  • Инлайнит не компилятор (жавак), а JIT.

                                    > он не заинлайнит и если тип понятный и описан строчкой выше
                                    Возможно и заинлайнит.

                                    Но опять же тип ArrayList, а он возвращает не ArrayList.Iterator<T>, а женерик Iterator<T>.
                                    То есть...
                                    Ответить
                                    • > То есть...

                                      ... надо заинлайнить list.iterator() и тогда мы узнаем, что там ArrayList.Iterator, у которого все методы тривиальны.
                                      Ответить
                                      • > тогда мы узнаем, что там ArrayList.Iterator, у которого все методы тривиальны

                                        Они-то тривиальны, но из реализации ArrayList мы узнаём что в сигнатуре iterator() НЕ УКАЗАН конкретный тип реализации:
                                        public Iterator<E> iterator() {
                                                return new Itr();
                                            }
                                            private class Itr implements Iterator<E> {
                                                int cursor;       // index of next element to return
                                                int lastRet = -1; // index of last element returned; -1 if no such
                                                int expectedModCount = modCount;
                                        
                                                Itr() {}
                                        
                                                public boolean hasNext() {
                                                    return cursor != size;
                                                }
                                        
                                                @SuppressWarnings("unchecked")
                                                public E next() {
                                                    checkForComodification();
                                                    int i = cursor;
                                                    if (i >= size)
                                                        throw new NoSuchElementException();
                                                    Object[] elementData = ArrayList.this.elementData;
                                                    if (i >= elementData.length)
                                                        throw new ConcurrentModificationException();
                                                    cursor = i + 1;
                                                    return (E) elementData[lastRet = i];
                                                }
                                        
                                                public void remove() {
                                                    if (lastRet < 0)
                                                        throw new IllegalStateException();
                                                    checkForComodification();
                                        
                                                    try {
                                                        ArrayList.this.remove(lastRet);
                                                        cursor = lastRet;
                                                        lastRet = -1;
                                                        expectedModCount = modCount;
                                                    } catch (IndexOutOfBoundsException ex) {
                                                        throw new ConcurrentModificationException();
                                                    }
                                                }
                                        Ответить
                                      • А это дефолтная реализация из AbstractList.Itr (которую по дефолту наследуют многие классы в т.ч. LinkedList)

                                        И подобных итераторов там десятки.
                                        private class Itr implements Iterator<E> {
                                        
                                                int cursor = 0;
                                                int lastRet = -1;
                                                int expectedModCount = modCount;
                                        
                                                public boolean hasNext() {
                                                    return cursor != size();
                                                }
                                        
                                                public E next() {
                                                    checkForComodification();
                                                    try {
                                                        int i = cursor;
                                                        E next = get(i);
                                                        lastRet = i;
                                                        cursor = i + 1;
                                                        return next;
                                                    } catch (IndexOutOfBoundsException e) {
                                                        checkForComodification();
                                                        throw new NoSuchElementException();
                                                    }
                                                }
                                        
                                                public void remove() {
                                                    if (lastRet < 0)
                                                        throw new IllegalStateException();
                                                    checkForComodification();
                                        
                                                    try {
                                                        AbstractList.this.remove(lastRet);
                                                        if (lastRet < cursor)
                                                            cursor--;
                                                        lastRet = -1;
                                                        expectedModCount = modCount;
                                                    } catch (IndexOutOfBoundsException e) {
                                                        throw new ConcurrentModificationException();
                                                    }
                                                }
                                        
                                                final void checkForComodification() {
                                                    if (modCount != expectedModCount)
                                                        throw new ConcurrentModificationException();
                                                }
                                            }
                                        Ответить
                                          • Притом из методов итератора вызываются другие виртуальные методы.

                                            Например hasNext() дёргает size(). Как и положено всякой школоте размер списка проверяется на каждой итерации.
                                            При том что по умолчанию эти классы не расчитаны на многопоточное использование.

                                            Этому коду на «Говнокод» самое место.
                                            Ответить
                    • Вспоминается занятный обсёр какой-то версии шарпушни, в которой
                      for (int i = 0; i < list.Length; i++) { list[i]... }

                      Компилялось в отлично оптимизированный код (чуть ли до уровня прямого движения уко-ко-ко-зателей), а вот на чём-то вроде
                      for (int i = 0; i < list.Length - 1; i++) { list[i]... }

                      Компилятор эпично обсирался и врубал не только bound-checking, но ещё и на каждой имперации вычислял «list.Length - 1» (кажется, аж с вызовом метода)!
                      Ответить
                      • какой багор) А Length он вычислял за O(N) я надеюсь, как длину строки в няшной?
                        Ответить
              • Годный сайт. Спасибо.

                Кнопка с бегущим питухом страусом. Мне уже нравится.
                Ответить
                • Он даже опенсорсный:
                  https://github.com/andreasfertig/cppinsights

                  Можно собрать у себя и прогонять через него проекты для C++17 и C++20, чтобы они потом на другой платформе собирались древним C++98. Ну или просто изучать, как устроены новые возможности языка.
                  Ответить
      • Дык всё просто. В foreach они закостылили новую переменную на каждой итерации, а тут так не прокатило.

        К слову, в шарпе этот "фикс" не особо то и нужен, всегда можно было скопировать i в локалку внутри блока. И с ней уже не будет граблей. Это не жс, где ради этого надо целую функцию городить.

        З.Ы. Именно поэтому я против захвата по ссылке.
        Ответить
        • То есть как был багор, таким он остался.

          https://ideone.com/muioFb
          Для foreach починили, для for забили.

          По мне вышло ещё хуже чем если бы не чинили.

          > а тут так не прокатило
          В обосраном ранее «JavaScript» let работает однообразно, вне зависимости от типа цикла.
          И var тоже работает однообразно.
          for (let i=0;i<3;++i) {
             setTimeout(() => console.log(i), 10); 
          }
          Ответить
          • Интересно как они сделали этот let. Невидимая временная переменная с тем же именем?
            Ответить
            • Довольно просто: создают на каждой итерации замыкание и хватают let by value, a var by reference.
              Ответить
              • Это каждый петух

                Кстати, «Борманд» участвовал в этом обсуждении, но это настолько нелогичная вещь (в смысле, что поведение из слов «let» и «var» ну никак не выводится), что не запомнилась:
                https://govnokod.ru/26280#comment518157
                Ответить
                • Да, действительно нетривиально. Они оба хватают by ref.
                  Просто Let локален для скоупа, при заходе в { } каждый раз это новая переменная.

                  Разницу между var и let наглядно иллюстрирует такой пример:
                  for (var i=0;i<10;++i){
                      var Var;
                      let Let;
                      Var = null==Var ? 0 : Var+1;
                      Let = null==Let ? 0 : Let+1;
                      console.log(Let,Var);
                  }

                  У Var остаётся прежний адрес.

                  А Let при заходе в скоуп каждый раз инициализируется новой переменной по новому адресу.

                  По этой причине замыкание хватает каждый раз новую ссылку. Но это именно ссылка.
                  Со всеми вытекающими проблемами.
                  Ответить
                  • Т. е. если замыкание изменит захваченное значение, а в цикле после вызова замыкания есть код, то он получит уже изменённое значение, поскольку это ссылка? А если бы был честный захват по значению, то код после замыкания получил бы старое значение?
                    Ответить
                    • Да.

                      Обосраться с let не просто легко, а ОЧЕНЬ легко
                      let i;
                      for (i=0;i<3;++i) {
                         setTimeout(() => console.log(i), 10); 
                      }

                      3 3 3

                      Т.к. let в верхнем скоупе, то это все три итерации одна и та же переменная.

                      А захват идёт по её ссылке.

                      Именно поэтому я за «PHP».
                      Ответить
                        • В реальном примере может понадобиться комплексный обход массива.

                          И как назло, for(let i будет в самом простом случае, когда и баг легко исправить.

                          А когда случай будет менее тривиальным, летонядь обосрётся:
                          let i = 0;
                          
                          while(i < pituxes.length && isRed(pituxes[i])) {
                            setTimeout(i, t);
                            i++;
                          }
                          
                          while(i < pituxes.length && isGreen(pituxes[i])) {
                            setTimeout(i, t);
                            i++;
                          }
                          
                          while(i < pituxes.length && isBlue(pituxes[i])) {
                            setTimeout(i, t);
                            i++;
                          }


                          Варвары с первых дней чтения мануалов узнавали про багор с циклами, заучивали конструкцию
                          for (var i; ...) (function(i){
                            ...
                          })(i);

                          и больше никогда у них ничего неправильного в функции не попалало.

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

                          Летоняди соснули. Бамп отсосу летонядей.
                          Ответить
                          • В ответ на аргумент что это не реальный пример привести ещё менее реальный пример это ахуенно

                            Никто никогда так не будет писать, все напишут один цикл и if внутри
                            Ответить
                            • Так и запишем: никто никогда не использует while. Ясно-понятно.
                              Ответить
                            • А как насчёт такого примера?
                              let i = pituxes.indexOf('pitux-nomernoy');
                              if (i < 0) bagorn;
                              for (; i<pituxes.length; i++) {
                                setTimeout(... i ...
                              }


                              У тех, кто пишет код, все три примера встречались в каком-либо виде.
                              Ответить
                              • это тоже можно сложить в тело цикла

                                ты можешь приводить хоть 20 таких же примеров и говорить что у тех кто пишет код регулярно возникают раздербанные циклы с произвольным вызовом setTimeout но это не так о чем я и говорю когда называю твои примеры не реальными
                                Ответить
                                • > говорить что у тех кто пишет код регулярно возникают раздербанные циклы с произвольным вызовом setTimeout но это не так о чем я и говорю когда

                                  Превет братик харашо пишеш
                                  []
                                    .map.call('bootcamp_dropout', (x,i) =>
                                      String.fromCharCode(x.charCodeAt(0) +
                                        [0,0,,-2,,,0,-15,15,0,-5,10,-4,0,1,-15][i]))
                                    .filter(x=>x!='\0').join('')


                                  > регулярно возникают раздербанные циклы с произвольным вызовом setTimeout но это не так

                                  Это почти так. Разумеется, не setTimeout, а какой-нибудь коллбек. Например, обход JSON, генерация контролов и обработчиков событий.

                                  Да, не в каждом цикле, но временами встречается.
                                  Ответить
                            • > Никто никогда так не будет писать, все напишут один цикл и if внутри

                              Вероятнее всего сперва напишут for (let i ...

                              А потом поменяется логика и for придётся заменить на цикл с постусловием.
                              let i=0;
                              do {
                              }while(...);

                              Обезьянка без задней мысли поменяет и даже не поймёт что она обосралась.
                              Ответить
                        • Реальный пример, который считает квадраты чисел.
                          let sqr=0;
                          for (let i=0;i<10;++i) {
                             sqr += 2*i+1;
                             setTimeout(function(){ console.log(sqr), 10}); 
                          }
                          И вот ради этой зумерской хрюкни мне ещё предлагают попердолиться с Babel, я правильно понимаю?
                          Ответить
                            • Вообще-то очень даже реальный.

                              Цикл с переменной аккумулятором крайне распространённый паттерн.
                              Ответить
                              • какой реальный пример )))
                                for (let i=0, sqr=0;i<10;++i) {
                                   sqr += 2*i+1;
                                   setTimeout(function(){ console.log(sqr), 10}); 
                                }
                                Ответить
                                  • > Даже в сижке будет работать

                                    В «Си» нет никаких «замыканий». Именно поэтому я за «Си».
                                    Ответить
                                    • Как в сижке эмулят замыкания?
                                      Делают callback и передают ему какой-нить void* вручную захватывая что нужно?
                                      Ответить
                                • Массив может быть двухмерным.

                                  Или в мире клиентухов это так же нинужно, как и циклы с постусловиями?
                                  let arr=[]; let N=3;
                                  for (let j=0;j<N;++j){
                                    if (null==arr[j]) arr[j]=[];
                                    for (let i=0;i<N;++i) {
                                        arr[j][i]=0|(Math.random()*10);
                                    }
                                  }
                                  
                                  for (let j=0, sum=0;j<N;++j){
                                    for (let i=0;i<N;++i) {
                                        sum+=arr[j][i];
                                          setTimeout( () => console.log("["+j+"]["+i+"] = "+sum),10 ); 
                                    }
                                  }
                                  Ответить
                                    • У тебя в браузерах никакой "дрисни" нет?
                                      Ответить
              • Т.е. изнутри цикла с let'ом теперь нельзя управлять циклом? Ну или изнутри лямбды нельзя, даже если её прям сразу позвать. Одно из двух.
                Ответить
                • > Т.е. изнутри цикла с let'ом теперь нельзя управлять циклом?
                  Думаю можно.

                  > Ну или изнутри лямбды нельзя, даже если её прям сразу позвать.
                  Полагаю там условный класс, в котором локальная копия i устанавливается при конструировании на каждой итерации.

                  Псевдокод:
                  class Lambda{
                      var i;
                      (){
                           console.log(i);
                      }
                  }
                  А в var там внутри ref i;

                  Но, повторюсь, как по мне все проблемы от того что программирующего заставляют смешивать образы императивного и функционального.

                  Если писать в одном, функциональном стиле, проблем по-просту не возникает
                  (1..3).forEach(function(){})
                  Ответить
                • > изнутри цикла с let'ом теперь нельзя управлять циклом?
                  > Ну или изнутри лямбды нельзя, даже если её прям сразу позвать. Одно из двух.
                  Оказывается можно

                  Пример 1024-- когда мутация захваченной питушни меняет ф-цию.
                  let x = 1;
                  let f = () => x;
                  f(); // 1
                  x = 2;
                  f(); // 2
                  То есть реализация там чуть сложнее чем я писал выше.

                  Выходит и var, и let оба захватывают по ссылке.
                  Только вот let не позволяет redefinition в скоупе.
                  И на каждой итерации генерится ссылка на новую переменную.
                  Ответить
  • я наверно уже забыл как c# компилиться.. но лябда не захватыает переменные?
    Ответить
    • Захватывает, и вот оказалось, что в .NET 3.5 захватывала по ссылке, а в .NET 4.x резко стала захватывать по значению.
      Ответить
      • спорить не буду... давно это было когда я написал последню строчку в cs2cpp 🙂
        Ответить
  • Вот это как-бы "неявное" захватывания чего-либо в объятия замыкания это всегда лажа говно и хуй

    Почему не сделать так, шоп программист явно выбирал что и как захватывать?
    Ответить
  • Constant Story "Hello Deductible";
     Constant Headline "^An Interactive Example^";
    
     Include "Parser";
     Include "VerbLib";
    
     [ Initialise;
         location = Living_Room;
         "Hello World";
     ];
    
     Object Kitchen "Kitchen";
     Object Front_Door "Front Door";
    
     Object Living_Room "Living Room"
         with
             description "A comfortably furnished living room.",
             n_to Kitchen,
             s_to Front_Door,
         has light;
    
     Object -> Salesman "insurance salesman"
         with
             name 'insurance' 'salesman' 'man',
             description "An insurance salesman in a tacky polyester
                   suit.  He seems eager to speak to you.",
             before [;
                 Listen:
                     move Insurance_Paperwork to player;
                     "The salesman bores you with a discussion
                      of life insurance policies.  From his
                      briefcase he pulls some paperwork which he
                      hands to you.";
             ],
         has animate;
    
     Object -> -> Briefcase "briefcase"
         with
             name 'briefcase' 'case',
             description "A slightly worn, black briefcase.",
         has container;
    
     Object -> -> -> Insurance_Paperwork "insurance paperwork"
         with
             name 'paperwork' 'papers' 'insurance' 'documents' 'forms',
             description "Page after page of small legalese.";
    
     Include "Grammar";
    Ответить
  • Пиздец зверье в гейдеве работает

    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
    Ответить

Добавить комментарий

Помни, guest, за тобой могут следить!

    А не использовать ли нам bbcode?


    8