1. Java / Говнокод #27041

    0

    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
    final class Point {
        public final int x;
        public final int y;
    
        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    
        // state-based implementations of equals, hashCode, toString
        // nothing else
    
    }

    is "just" the data (x, y). Its representation is (x, y), its construction protocol accepts an (x, y) pair and stores it directly into the representation,
    it provides unmediated access to that representation, and derives the core Object methods directly from that representation.
    And in the middle, there are grey areas where we're going to have to draw a line.

    Other OO languages have explored compact syntactic forms for modeling data-oriented classes: case classes in Scala, data classes in Kotlin, and record classes in C#.
    These have in common that some or all of the state of a class can be described directly in the class header -- though they vary in their semantics
    (such as constraints on the mutability or accessibility of fields, extensibility of the class, and other restrictions.)

    Committing in the class declaration to at least part of the relationship between state and interface enables suitable defaults to be derived for many common members.
    All of these mechanisms (let's call them "data classes") seek to bring us closer to the goal of being able to define Point as something like:

    record Point(int x, int y) { }

    [u]https://openjdk.java.net/jeps/359
    https://cr.openjdk.java.net/~briangoetz/amber/datum.html[u]

    Запостил: 3.14159265, 19 Октября 2020

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

    • Restrictions on records

      Records cannot extend any other class, and cannot declare instance fields other than the private final fields which correspond to components of the state description. Any other fields which are declared must be static. These restrictions ensure that the state description alone defines the representation.

      Records are implicitly final, and cannot be abstract. These restrictions emphasize that the API of a record is defined solely by its state description, and cannot be enhanced later by another class or record.


      Прошло 25 лет и в «Йажа» наконец-то завезли Сишный struct;
      record Point(int x, int y) { }

      struct Point {int x; int y;}
      Ответить
      • Хотя нет, подождите, завезли, но не совсем.

        Пужулуйста, подожите ещё лет 5, пока мы допилим передачу на стеке и компактные аллокации.

        Are records the same as value types?

        With value types coming down the road through Project Valhalla, it is reasonable to ask about the overlap between (immutable) data classes and value types, and as whether the intersection of data-ness and value-ness is a useful space to inhabit.

        Records and value types have some obvious similarities; they are both immutable aggregates, with restrictions on extension. Are these really the same feature in disguise?

        When we look at their semantic goals, we can see that they differ. Value types are primarily about enabling flat and dense layout of objects in memory.


        В общем:
        https://www.youtube.com/watch?v=Fm5Ust7vEhk
        Ответить
        • > Пужулуйста, подожите ещё лет 5

          зашел написать ровно вот это
          Ответить
          • Надо не забыть лет через пять проверить.
            Ответить
        • Ну как, допилили?
          Ответить
    • Ебать-колотить, всего только четверть века прошло, а питухи поняли что вот это вот пиздец:
      public final class Point {
        private final int myX;
        private final int myY;
      
        public Point(int x, int y) {
          myX = x;
          myY = y;
        }
      
        public int getX() {
          return myX;
        }
      
        public int getY() {
          return myY;
        }
      
        @Override
        public boolean equals(Object o) {
          if (this == o) return true;
          if (o == null || getClass() != o.getClass()) return false;
          Point point = (Point)o;
          return myX == point.myX && myY == point.myY;
        }
      
        @Override
        public int hashCode() {
          return Objects.hash(myX, myY);
        }
      }
      Ответить
      • Да.

        Если бы в Сишке стандартизировали #pragma pack(1) или другую подобную фичу, вот эту бойлерплейт-питушню с equals можно было бы заменить одним memcmp.

        Заодно компилер мог бы высирать ворнинги про возможный unaligned access.

        Но меня больше всего веселит что жавухи ПРИНЦИПИАЛЬНО отказались от наследования.
        Ответить
        • Угу, в сишечке нельзя структуры через ==, и это пижня.

          А в коко датаклассы и в c# можно

          >ПРИНЦИПИАЛЬНО отказались от наследования.
          Ну вот сравнение бы у нас могло и обламаться.

          Разве ли ребенок родителю с такими же полями?
          А родитель ребенку?

          В коко дата классы не наследуются
          Ответить
          • На самом деле можно, поскольку #pragma pack(1) поддерживают основные мейнстрим компилеры.
            Поскольку гцц бекпортировали эту фичу у мс.
            А шланг старается не отставать от гцц.

            https://docs.microsoft.com/en-us/cpp/preprocessor/pack?view=vs-2019
            https://gcc.gnu.org/onlinedocs/gcc/Structure-Layout-Pragmas.html
            Ответить
            • а почему не завести в стандарт?
              Ответить
              • Потому что тогда всем придётся поддерживать. А для некоторых платформ это пиздец-пиздец, придётся эмулировать невыровненные чтения софтварно.
                Ответить
                • Так ведь гцц и так поддерживает трилионы платформ.

                  >придётся эмулировать невыровненные чтения софтварно
                  Ну выдавать ворнинг: внимание, ваша программа будет жутко тупить.
                  Ответить
                  • Кстати, а в стандарте хоть одна прагма то есть?

                    Вот ту же #pragma once почему бы не добавить? Она вроде никому ничего плохого не сделает, зато куча бройлейрплейта уйдёт.
                    Ответить
                    • Да, инклуд гарды это лулз.

                      Не понятно, почему не завести такое. Может быть потому, что где-то его сложно реализовать?
                      Ответить
                      • Просто стандартизаторы мудаки и занимаются какой-то хуйнёй вместо Make C great again.
                        Ответить
                      • Пишут, что проблема в симлинках, хардлинках и копиях.

                        З.Ы. Хотя считали бы хеш от контента да и всё. Если файлы физически одинаковые, какой смысл их инклудить 2 раза? Инклуд гарды точно так же бы отработали в них.
                        Ответить
                        • >хеш от контента
                          а не воткнёт по пифомансу?
                          Ответить
                          • файл и так и так читать надо целиком, вряд ли
                            Ответить
                        • Её поддерживают джва десятка конпеляторов.

                          Не осилил? Оставайся C89-совместимым, делов-то.
                          Ответить
                          • Ну так то да. Написали бы, что в хитровыебанных случаях в духе симлинков и копий она implementation defined.
                            Ответить
                            • >в хитровыебанных случаях в духе симлинков и копий она implementation defined

                              Тем более в крестах (и в сишке) сплошь и рядом такое.

                              ­­— Corner case?
                              — Сам себе злобный багор.
                              Ответить
          • И в «Паскале» нельзя:
            https://ideone.com/83sfAO

            И массивы тоже.
            https://ideone.com/RooEZm

            Хотя копировать структуры и массивы можно (тут именно копируются значения, а указатель не изменяется):
            https://ideone.com/VrSjb0
            Ответить
        • > или другую подобную фичу

          Стабильную сортировку полей в порядке убывания размера алаймента.
          Ответить
          • > Стабильную сортировку полей в порядке убывания размера.

            Но иногда уместнее паковать по 32-битным границам
            struct { 
              int32_t a;
              char    b[3];
              char    c;
              char    d;
              char    e[3];
            }

            Чтобы чтение char[3] шло одним 32-битным куском. Или сортировка сугубо опциональна?
            Ответить
            • > Чтобы чтение char[3] шло одним 32-битным куском.

              Х.з., сомнительная какая-то оптимизация. Мы же не знаем какой там паттерн обращений будет, вдруг там просто рандомный доступ. Такое уже только руками раскладывать. Ну а сортировка стабильная как раз ради того, чтобы такие конструкции не сломать.
              Ответить
              • >Х.з., сомнительная какая-то оптимизация. Мы же не знаем какой там паттерн обращений будет, вдруг там просто рандомный доступ.

                может получица фолс шаринг, да?
                Ответить
                • Да не, просто не будет профита от того, что оно на что-то там выровнено. Чар и чар.
                  Ответить
                  • ну да, для фолс шаринга нужно чтобы туда разные треды ходили, пропутил
                    Ответить
                    • Ну и для устранения фолс шаринга надо гораздо дальше раскидывать.

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

                        Там ещё есть прикол с ассоциативностью, что например каждые 4 мегабайта попадают в одну и ту же кеш-линию.
                        Ответить
                      • {
                            const int hbd = p->p.bpc > 8;
                            const int aligned_w = (p->p.w + 127) & ~127;
                            const int aligned_h = (p->p.h + 127) & ~127;
                        
                        -    p->stride[0] = aligned_w << hbd;
                        -    p->stride[1] = has_chroma ? (aligned_w >> ss_hor) << hbd : 0;
                        -    const size_t y_sz = p->stride[0] * aligned_h;
                        -    const size_t uv_sz = p->stride[1] * (aligned_h >> ss_ver);
                        -    const size_t pic_size = y_sz + 2 * uv_sz;
                        -
                        -    uint8_t *data = alloc_aligned(pic_size + PICTURE_ALIGNMENT,
                        -                                        PICTURE_ALIGNMENT);
                        -    if (data == NULL) {
                        -        return ERR(ENOMEM);
                        -    }
                        +    ptrdiff_t y_stride = aligned_w << hbd;
                        +    ptrdiff_t uv_stride = has_chroma ? y_stride >> ss_hor : 0;
                        +    /* Due to how mapping of addresses to sets works in most L1 and L2 cache
                        +     * implementations, strides of multiples of certain power-of-two numbers
                        +     * may cause multiple rows of the same superblock to map to the same set,
                        +     * causing evictions of previous rows resulting in a reduction in cache
                        +     * hit rate. Avoid that by slightly padding the stride when necessary. */
                        +    if (!(y_stride & 1023))
                        +        y_stride += PICTURE_ALIGNMENT;
                        +    if (!(uv_stride & 1023) && has_chroma)
                        +        uv_stride += PICTURE_ALIGNMENT;
                        +    p->stride[0] = y_stride;
                        +    p->stride[1] = uv_stride;
                        +    const size_t y_sz = y_stride * aligned_h;
                        +    const size_t uv_sz = uv_stride * (aligned_h >> ss_ver);
                        +    const size_t pic_size = y_sz + 2 * uv_sz + PICTURE_ALIGNMENT;
                        +    uint8_t *data = alloc_aligned(pic_size, PICTURE_ALIGNMENT);
                        +    if (!data) return ERR(ENOMEM);
                        Ответить
        • > ПРИНЦИПИАЛЬНО отказались от наследования

          Да и правильно. Почему бы просто не вложить структуру как поле, как это десятилетиями делали в сишке?

          Ну какой нафиг наследник из структуры с джвумя дополнительными полями?
          Ответить
          • наследование вообще рак и не нужно в 99.9%
            Ответить
          • Смешно, что одни из главных адептов ООП наконец-то признали что они конкретно йажанулись.

            > Records cannot extend any other class
            > These restrictions emphasize that the API of a record is defined solely by its state description, and cannot be enhanced later by another class or record.
            Ответить
        • Наследование там нельзя добавлять, потому что иначе не получится сделать аналог struct из шарпа.
          Ответить

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