1. Куча / Говнокод #12482

    +130

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    import std.stdio; 
    class Parent{ } 
    class Another{ } 
    class Child: Parent
    {
      Another data;
      alias data this;  
      this()
      {
      data = new Another;
      }
    }
     void test(Parent t){writeln("Parent: ", t);}
     void test(Another t){writeln("Another: ", t);}
     void main() { 
        auto Me = new Child();    
        test(Me);
    }

    Интуитивного свежачка вам.
    http://ideone.com/qEDzz
    http://ideone.com/9mB8S

    Запостил: LispGovno, 27 Января 2013

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

    • Очень хочу это в кресты:
      http://dlang.org/function.html#pure-functions
      Ответить
      • а смысл? судя по описанию это однозначно premature optimization.

        вот immutable объекты в STL/C++/етц как по были бы мне более полезны. но они там никогда не появятся, потому что полиморфизм производительность снизит. :(
        Ответить
        • Как чистые функции связаны с преждевременной оптимизацией? Они связаны с уменьшением числа ошибок, с бесплатной оптимизацией кода компилятором и с увеличением скорости компиляции.

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

            может быть. пока нужды в этом не видел. а приори я не против. :)

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

            > Как immutable связан с полиморфизмом?

            я секретный фанат ObjC стиля. в С++ у тебя например `const vector<>` и `vector<>`. а в ОбжС `NSArray` и `NSMutableArray`, и NSMutableArray унаследован от immutable NSArray.

            ключевая разница между языками в том что если тебе надо слобать кастом ридонли контейнер, то в С++ для поддержания совместимости с STL надо реализовавывать еще в добавок кучку левых методов для модификации. потому что `const`ность зависит от контекста, а не от самого объекта. в ObjC достаточно реализовать только методы для чтения, потому что констность есть свойстно самого контейнера. но для полноценной работы этого всего нужен полиморфизм, что бы от immutable класса можно было унаследовать mutable класс и перекрыть ридонли варианты методов - потому что представление данных в immutable и mutable контейнерах может отличатся.

            неоднократно делал это в С++, но с ограниченым успехом. основная проблема как всегда это совместимость с STL, который хочет итераторы. тут то грабли и начинаются так как констноть итераторов зависит от контекста, а не от объекта...
            Ответить
            • Наследовать мутабельные структуры от иммутабельных - моветон, т.к. это ломает семантику. Мутабельный массив не является иммутабельным по определению. Но разделение их в разные иерархии с некоторой общей абстрактной базой выглядит неплохой идеей, которая, кстати, реализована в Scala.
              В C++ всё веселее, ведь там есть попытка подтвердить иммутабельность объектов (хотя бы бинарную) на уровне компиляции. От этого решения есть как два плюса, так и минусы.
              Ответить
              • Каким образом это ломает семантику? Приведи примеры кода в которых это происходит? Зачем отдельно заводить немутабильную базу и немутабильный массив потомок, если их можно совместить?
                Ответить
                • >Каким образом это ломает семантику?

                  >Мутабельный массив не является иммутабельным по определению. *

                  * наследование подразумевает, что если
                  A extends B
                  , то
                  A instanceof B
                  , а тогда получается что
                  myMutableArray: MutableArray = ...; myMutableArray instanceof ImmutableArray
                  - т.е. мутабельный массив является (по определению наследования и исходя из описанной выше иерархии NSArray и NSMutableArray) иммутабельным. Такой результат в реальной программе может привести к смерти брата.
                  Ответить
                  • в c++ нет понятия иммутабельный насовсем, есть понятие - иммутабельный в пределах блока (при передаче в функцию)
                    поэтому для какого то блока мутабельный массив вполне является иммутабельным, и к смерти брата это не приведет

                    является ли в данном случае вовлечение наследования только для code reuse, или его тут действительно можно использовать - я бы пообсуждал
                    потому что недавно как раз имплементил нечто подобное, где мутабельный объект наследовался от иммутабельного (без костылей с виртуальностью)
                    Ответить
                    • >иммутабельный в пределах блока (при передаче в функцию)

                      А как в таком случае с многопоточностью? Если я захочу один и тот же массив в одну функцию передать, как мутабельный, а в другую - как иммутабельный, и функций будут выполняться параллельно - что произойдет?
                      Ответить
                      • Я уже ниже пояснил:
                        http://govnokod.ru/12482#comment168293
                        Нужен NImmutableArray. Он же immutable в D. Он же непогрешимый, а не логический const. Для таких проблем с массивом при многопоточной работе - нет.
                        Ответить
                      • то и произойдет - функция, рассчитывающая на константность, легко может с этим обломаться
                        поэтому надо лочить r/w доступ к контейнеру (ну или копировать по значению/велосипедить cow, что попахивает)
                        Ответить
                      • Уже всё сказали, я лишь повторю, что слово const нужно только компилятору, с помощью него он может кой-чего оптимизировать и частично проверить корректность использования. То, о чём ты говоришь - это уже область рантайма, там нужна синхронизация, как с любым разделяемым ресурсом.
                        Ответить
              • "Наследовать мутабельные структуры от иммутабельных - моветон, т.к. это ломает семантику."

                что ты куришь? слишком много жабы??

                само собой разумеется что мутабельный объект наследуется от немутабельного, что бы его можно было передавать как параметр туда где достаточен немутабельный объект.

                таже самая фигня и в С++: не-конст объектом можно пользоватся и как не-конст и как конст, конст объектом можно пользоватся только как конст.

                "В C++ всё веселее, ведь там есть попытка подтвердить иммутабельность объектов (хотя бы бинарную) на уровне компиляции."

                много асма для С++ видел. некоторый даже в деталях расковыривал. разницы от констности в кодогенерации, по крайней мере на с++98, не видел.
                Ответить
                • const и мутабельность - по смыслу две разные вещи.

                  В Scala, если идентификатор объявлен как var, то его значение позже можно заменить на другое (идентификатор/ссылка не является константой). Но при этом текущее значение может быть как мутабельным, так и иммутабельным.

                  Если идентификатор объявлен как val, то его значение нельзя заменить на другое (ссылка постоянна). Но при этом само значение, на которое указывает идентификатор, может быть как мутабельным, так и иммутабельным.

                  В большинстве языков такого различия не делается, отсюда бардак в головах (некоторых) программистов.

                  >само собой разумеется что мутабельный объект наследуется от немутабельного, что бы его можно было передавать как параметр туда где достаточен немутабельный объект.

                  Этого достаточно для соблюдения принципа подстановки Лисков ТОЛЬКО при условии, что передаваемый объект используется одним потоком. Если имеем многопоточное приложение, то у меня для вас плохие новости: когда мы передадим мутабельный объект под видом иммутабельного, то все наши предположения о нем, как об иммутабельном, в общем случае окажутся неверны. Вы сами можете догадаться, почему.

                  Более того, это действительно является совершенным бредом с семантической точки зрения ("мутабельный объект является иммутабельным"). Я пояснил это в http://govnokod.ru/12482#comment168282
                  Ответить
                  • > Вы сами можете догадаться, почему.

                    а. ты о этом. не ну это само собой разумеется. но это проблема только для многопоточности. а в многопоточности за что ни возмись, все проблема. поэтому то многопоточность и остается нишей. только языки которым одного ядра мала ею и злоупотребляют. ;)

                    иммутабл объекты они мне больше полезны как утилита которая позволяет экономить память и избегать лишних копирований. потенциальная возможность наследования мутабл от иммутабл для меня всего лишь бонус. с мутабл объекта иммутабл копию всегда сделать можно (что уже является нормой для большинства языков и стандартных библиотек).

                    самое успешное использование иммутаблов у меня было в программе где жутко большой кусок текста (несколько гигов) зачитывался в память, пихался в доморощеную иммутабл строку, и потом по всей программе использовались иммутабл подстроки этой большой иммутабл строки.
                    Ответить
                    • И так мы пришли, как и ожидалось, к понятию логической константности и непогрешимой константности, тоесть const и immutable из D:
                      http://dlang.org/const3.html

                      И опять же пришли предположительно, тк Роман не откликнулся, к скаловской иерархии:
                      class NConstArray;
                      class NImmutableArray: public NConstArray;
                      class NMutableArray: public NConstArray;
                      Ответить
                      • Массивы в Scala мутабельны. А вот коллекции разнесены на два пакета: scala.collection.mutable и scala.collection.immutable. В иммутабельные можно добавлять элементы, при этом порождается новая коллекция, исходная остаётся неизменной.
                        Ответить
            • > для поддержания совместимости с STL надо реализовавывать еще в добавок кучку левых методов для модификации
              это конструктор копирования и оператор присваивания, чтоли?
              что имеется в виду под совместимость с stl?
              Ответить
              • > что имеется в виду под совместимость с stl?

                способность использовать все стандартные фишки из например algorithm. так же как минимум синтаксическая совместимость с STL что бы в пользовательском коде сильно кастом контейнеры от STL контейнеров не отличались.

                > это конструктор копирования и оператор присваивания, чтоли?

                главные грабли - итераторы. и с ними идущие find()/begin()/end(). erase() по итератору. resize(). (push|pop)_(front|back).

                да всего уже не помню. помню что GCCшные ошибки типа "невозможно инстанциировать темплейт потому что" и 20-50 строк кракозябель не были сильной помощью.

                помню только мораль сей басни: если проект сидит на STL, то велосипед не стоит усилий.
                Ответить
                • если контейнер иммутабелен, то какой по нему еще erase или resize?
                  итераторы легче сделать через boost.iterator_facade
                  а 20-50 строк нечитабельного текста ошибки - это, обычно, результат проверки на "концепт" типа RandomAccess или Bidirectional - как благодарность комитету, что не приняли нормальных концептов
                  Ответить
                  • да.

                    > если контейнер иммутабелен, то какой по нему еще erase или resize?

                    про то же и речь. в С++/STL нет концепции immutable - поэтому приходится реализовывать лишние методы просто потому что в каком темплейте упоминается метод. по логике программы он не будет вызыватся, то как минимум заглушку надо добавлять, что бы темплейт мог инстанциироватся.
                    Ответить
                    • Если метод не будет вызываться, то нахрен ему инстанцироваться? Поэтому в интерфейс добавлять и реализовывать не нужно.
                      Ответить
                      • "Если метод не будет вызываться, то нахрен ему инстанцироваться?"

                        потому что другой темплейт класс на него ссылается. даже если методы которые на него ссылаются не используются, компилеры (некоторые? все? хез, у меня обмавалась компиляция с ошибкой и на гцц 3 и на паре комерческих) требуют/требовали наличие оного.
                        Ответить
                        • Шаблоны имеют право инстанцировать не существующие шаблоны пока не попытаются инстанцироватся сами.
                          Ответить
                          • и как это должно помочь? или ты хочешь сказать что вот это скомпилируется?

                            template<class A>
                            struct whatever {
                               A a;
                               void method1() { a.method1(); }
                               void method2() { a.method2(); }
                            };
                            template<class B>
                            struct foobar {
                               void method1 () { /* ... */  }
                            };
                            whatever<foobar<int>> o;
                            o.method1();


                            потому что Н лет назад именно вот такого типа код у меня и не компилировался.
                            Ответить
                    • можно пример какие методы все же нужно?

                      все темплейты из algorithm работают и с сырыми указателями, поэтому все что нужно от итераторов - дереференс, инкремент, при рандом аксесс - смещение на n, ну и если он мутабелен - дереференс должен возвратить T&, если не мутабелен - не должен

                      поэтому есть в контейнерах iterator, а есть const_iterator, потому что в половине случаев стл контейнеры сами используются в ситуации, где они строго константны

                      там в algorithm вроде ни одной функции нет, которая бы не с итератором, а с контейнером работала
                      Ответить
                  • >RandomAccess или Bidirectional - как благодарность комитету, что не приняли нормальных концептов


                    Категорию стасик_ассертом проверить и все. А вот то что нет отдельной ортогональной категории для writable и readable - это упущение.
                    Ответить
                    • Кстати, по моему про writable и readable я глупость сказал. Заткните уши.
                      Ответить
        • Судя по всему, это однозначно левое применение быдлолозунга про оптимизацию.
          Ответить
    • import std.stdio; 
      class Parent{} 
      class Another{ } 
      class Child: Parent
      {
        Another data;
        alias data this;
      } 
      void main() { 
              auto Me = new Child();
              writeln(Me);            //Class.child
              writeln(cast(Child)Me); //Class.child
              writeln(cast(Parent)Me);//null!!!
              writeln(cast(Another)Me);//null
      }

      Кто на свеженького?
      http://ideone.com/rm3li
      Ответить
      • тут небось тоже приватное наследование, как в крестах?
        Ответить
        • Приватного наследования в D нет, зато есть попытка перегрузить operator. и implicit operator Type на уровне языка через alias. Похоже должно быть на скаловские имплиситы
          Ответить
      • где тут свежачок?
        >246 days 20 hours ago
        Ответить
    • import std.stdio; 
      class Foo{} 
      class Bar
      {
        Foo data;
        alias data this;
        this() 
        {
          data = new Foo();
        }
      } 
      void test(Foo t){writeln("Foo: ", t);} 
      void main() { 
          auto Me = new Bar();    
          test(Me);
      }

      Свежачок свежачок, налетай, компиляй:
      http://ideone.com/7xmyx
      Ответить
    • import std.stdio; 
      class Foo{} 
      class Bar
      {
        Foo data;
        alias data this;
      } 
      void test(Foo[] arr)
      {
      foreach(el; arr)
      writeln("Foo: ", el);
      } 
      void main() { 
          Foo[4] Me = [ new Foo(), new Foo(), new Bar(), new Foo()];    
          test(Me);
      }

      Свежачок свежачок, очень вкусный слушай:
      http://ideone.com/sS9rc
      Ответить
    • Опять с ГД.ру код напыжженный.
      LispGovno, ну как не стыдно?
      Ответить
    • Тред не читал. D не знаю. Прозреваю что загвоздка всех примеров в магической строчке:
      alias data this;
      Ответить
    • Я нихуя не понял в этом коде.
      Ответить
      • В данном случае это совсем не обидно.
        Ответить
      • а что ты не осилил говоришь?
        Ответить
        • Почему указатель на Child, инициализированный как new Child, думает, что он - указатель на Another, причём нулевой?
          Ответить
          • Известно что с ингришем ты не особо дружишь.
            И что слова alias в поцкалике нету?
            Ответить
            • В крестоблядском языке тоже нету.
              То, что оно означает "синоним", то есть "два названия для одного и того же" (это я добавил, чтобы ты не подумал, что я залез в гуглопереводчик и скопировал оттуда умное слово, не зная его смысл), нихуя не проясняет того, как же всё-таки расположены поля в этой структуре.
              Ответить
              • >>Почему указатель думает, что он - указатель на Another, причём нулевой?
                >>как же всё-таки расположены поля в этой структуре.
                Та нет никакой структуры
                Another data;//data=null
                alias data this;  //this=data=null
                this()  {  data = new Another;  } /*хз что тут происходит. 
                возможно утечка памяти. собственно суть говна*/
                Ответить

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