На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела:
1. Название темы - краткое описание кто/что против кого/чего
2. В первом сообщении - список параметров, по которым идет сравнение.
3. Старайтесь аргументировать свои высказывания. Фразы типа "Венда/Слюникс - ацтой" считаются флудом.
4. Давайте жить дружно и не доводить обсуждение до маразма и личных оскорблений.
Модераторы: Модераторы, Комодераторы
Страницы: (33) « Первая ... 8 9 [10] 11 12 ...  32 33  ( Перейти к последнему сообщению )  
> trait + impl vs class , навеяно Rust'ом
    Цитата MyNameIsIgor @
    Так ведь
    Какой-то детский сад. Я-то думал, что тебе есть, что сказать, мало ли, вдруг чего-то не знаю.

    Иначе проще будет забить и позволить компилятору ругаться в месте применения переданной функции, чем городить огород имеющими средствами. В крайнем случае, воткнуть static_assert с использованием boost::function_traits (и да, я в курсе, что там тоже SFINAE внутри).

    Ну и я уже нашёл, что в D оно таки есть из коробки - arity, ReturnType, ParameterTypeTuple и т.д.

    Собственно, что хотел сказать - в С++ у нас или такие костыли (справедливости ради, они не особо часто и нужны) или std::function с лишним выделением памяти. В расте мало того, что оно делается легко, так что ещё и выглядит почти одинаково:
    ExpandedWrap disabled
      fn test_static<T: Fn(i32) -> i32>(f: T) {
          println!("{}", f(10));
      }
       
      fn test_dynamic(f: &Fn(i32) -> i32) {
          println!("{}", f(20));
      }
       
      fn foo(a: i32) -> i32 {
          a + 10
      }
       
      fn main() {
          test_static(foo);
          test_dynamic(&foo);
      }
      Цитата DarkEld3r @
      И никакого динамического полиморфизма.
      Я правильно понимаю? Нам потребуется отдельный трейт для каждого сериализуемого типа? То есть в D я просто создал структуру и вызвал serialize. А в Rust для каждой сериализуемой структуры придется городить свой кастомный трейт?
        Цитата DarkEld3r @
        Какой-то детский сад.

        Т.е. вас только в детском саду просили отвечать за свои слова?
        Цитата DarkEld3r @
        Я-то думал, что тебе есть, что сказать

        Возможно есть, возможно - нет. В любом случае я хочу, чтобы слушающий обладал достаточным интеллектом, чтобы понять сказанное.
        Цитата DarkEld3r @
        мало ли, вдруг чего-то не знаю

        Не знаете. Начните заполнять прорехи в вашем образовании с понятия "интерфейс".
        Цитата DarkEld3r @
        воткнуть static_assert

        Это правильное решение, если не требуется перегрузка по сигнатуре функции. Ах, да, в Rust же перегрузки нет :crazy:
        Цитата DarkEld3r @
        с использованием boost::function_traits

        Не нужно, ибо не переварит перегрузку operator().
        Цитата DarkEld3r @
        и да, я в курсе, что там тоже SFINAE внутри

        Кто подсказал?
          Цитата DarkEld3r @
          Ну про enum (очень поверхностно) в курсе. Значением ведь может быть любой тип?
          Почти. Классы и указатели на структуры точно не могут.
          Цитата DarkEld3r @
          Ну и раз, "по разному", то может ещё пару вариантов приведёшь? A то бегло не нагуглить не удалось.
          Присвоить результат функции глобальной или статической const/immutable переменной, передать результат в качестве параметра шаблона, вызвать эту функцию внутри шаблона в процессе инстанцирования.

          Добавлено
          Цитата DarkEld3r @
          Ну и я уже нашёл, что в D оно таки есть из коробки - arity, ReturnType, ParameterTypeTuple и т.д.

          Собственно, что хотел сказать - в С++ у нас или такие костыли (справедливости ради, они не особо часто и нужны) или std::function с лишним выделением памяти. В расте мало того, что оно делается легко, так что ещё и выглядит почти одинаково:
          В D для такого примитива не нужны ни arity ни ReturnType ни ParameterTypeTuple:
          http://dpaste.dzfl.pl/6e83bb30275a
          ExpandedWrap disabled
            import std.stdio;
             
            void test_static(T: int function(int))(T foo) {
                foo(10).writeln;
            }
             
            void test_dynamic(int function(int) foo) {
                foo(20).writeln;
            }
             
            int foo(int a) {
                return a + 10;
            }
             
            void main() {
                test_static(&foo);
                test_dynamic(&foo);
            }
          Сообщение отредактировано: applegame -
            Цитата applegame @
            Я правильно понимаю? Нам потребуется отдельный трейт для каждого сериализуемого типа? То есть в D я просто создал структуру и вызвал serialize.
            Да, придётся.

            Правильно я понимаю, что в D для структур ты будешь сериализовать все члены? В общем случае, это ведь некорректно. С тем, что удобнее иметь такое поведение по умолчанию с возможностью запретить сериализацию отдельных полей спорить не буду.

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

            Цитата MyNameIsIgor @
            Начните заполнять прорехи в вашем образовании с понятия "интерфейс".
            Газификация луж продолжается.

            Добавлено
            Цитата applegame @
            В D для такого примитива не нужны ни arity ни ReturnType ни ParameterTypeTuple:
            Ок, спасибо. Второй вариант - это просто указатель на функцию или аналог плюсового std::function? Если первое, то немного не то.

            А вот с шаблоном интересно, жаль в С++ так нельзя.
            Сообщение отредактировано: DarkEld3r -
              А вот для ситуации, когда функция должна принять любой callable тип c заданными параметрами, а не только собственно функцию, эти трейты пригодятся:
              http://dpaste.dzfl.pl/2d66a35eff90
              ExpandedWrap disabled
                import std.stdio;
                import std.traits;
                import std.typetuple;
                 
                void test(T)(T foo) if(
                    isCallable!T &&
                    is(ReturnType!T == int) &&
                    is(ParameterTypeTuple!T == TypeTuple!int)
                ) {
                    foo(10).writeln;
                }
                 
                int foo(int a) {
                    return a + 10;
                }
                 
                struct Bar {
                    int opCall(int a) {
                        return a + 20;
                    }
                }
                 
                int baz(short a) {
                    return a + 30;
                }
                 
                 
                void main() {
                    test(&foo);
                    Bar bar;
                    test(bar);
                    // test(&baz); // fail
                }

              Rust так умеет? В C++ кстати это тоже возможно, правда несколько сложнее.

              Добавлено
              Цитата DarkEld3r @
              Ок, спасибо. Второй вариант - это просто указатель на функцию или аналог плюсового std::function? Если первое, то немного не то.
              Это указатель, а в Rust это что? В D аналог std::function не нужен, его заменяют лямбды (а точнее делегаты), которые, в отличие от C++, имеют четко описанный тип зависящий только от параметров и возвращаемого значения.

              Добавлено
              Цитата DarkEld3r @
              Правильно я понимаю, что в D для структур ты будешь сериализовать все члены? В общем случае, это ведь некорректно. С тем, что удобнее иметь такое поведение по умолчанию с возможностью запретить сериализацию отдельных полей спорить не буду.
              Не обязательно все. В D можно еще указывать user defined attributes, которые также возможно читать compile-time. С помощью них можно задавать всякие флажки. Типа:
              ExpandedWrap disabled
                struct Data {
                    int field;
                    @ignored {
                         string ignoredString;
                         int ignoredInt;
                    }
                    @name("zoo") short _un_readableNamed_;
                }
              Сообщение отредактировано: applegame -
                Цитата applegame @
                Rust так умеет?
                "Теоретически". Выше в примерах кода (Fn(i32) -> i32), Fn - это как раз трейт. Их есть три вида: Fn, FnMut и FnOnce. Лямбды - это как раз сахар для этих трейтов. Для своего типа этот трейты, по идее, тоже можно реализовать, но сейчас это "нестабильная фича". Попробовал набросать пример, для этого надо "переключаться" на "ночной" раст - в стабильных реализах нестабильные вещи использовать запрещено. Получил "internal compiler error" и предложение отправить баг-репорт. :)

                Цитата applegame @
                Это указатель, а в Rust это что?
                "Трейт-обьект", по сути - это как раз аналог std::function. Ну или той обёртки, что ты делал когда демонстрировал добавление реализации интерфейса.

                Цитата applegame @
                его заменяют лямбды (а точнее делегаты), которые, в отличие от C++, имеют четко описанный тип зависящий только от параметров и возвращаемого значения.
                В расте у callable сущностей тоже один тип - Fn/FnMut/FnOnce (в зависимости от сигнатуры). Вне зависимости от того лямбда это, функция или тип с вручную реализованными нужными трейтами.

                Что это будет в итоге - зависит от использования. Если дженерик, то заинлайнится. Если ссылка/указатель на трейт - то будет "обёртка".

                Цитата applegame @
                В D можно еще указывать user defined attributes
                В расте, "пока что", нельзя (есть сколько-то готовых), но планы добавить свои есть.

                Кстати, любопытно - как в D разруливаются конфликты имён в атрибутах?

                Цитата applegame @
                С помощью них можно задавать всякие флажки.
                Но в чужой тип их ведь не впихнёшь?
                Сообщение отредактировано: DarkEld3r -
                  Цитата DarkEld3r @
                  Но в чужой тип их ведь не впихнёшь?
                  В смысле не впихнешь? В D UDA - это либо произвольный тип, либо значение.

                  ExpandedWrap disabled
                    struct MySuperAttribute {
                        int a;
                    }
                     
                    enum attr1 = MySuperAttribute(2);
                    enum attr2 = MySuperAttribute(3);
                    alias attr3 = MySuperAttribute;
                     
                    struct Bar {
                    }
                     
                    struct Foo {
                        @attr1 int f1;
                        @attr2 int f2;
                        @attr3 int f3;
                        @attr3(2) int f4;
                        @Bar int f5;
                        @("string", 10, Bar) int f6; // несколько атрибутов
                    }

                  Цитата DarkEld3r @
                  Кстати, любопытно - как в D разруливаются конфликты имён в атрибутах?

                  Решаются также, как конфликты имен типов.
                  Сообщение отредактировано: applegame -
                    Цитата applegame @
                    Стандарт C++ разве требует чтобы потомок имел тот же размер, что и предок, в случаях когда не добавляются дополнительные данные?
                    В целом да. Явно этого не говорится, однако это следует из некоторых пунктов, описывающих лэйаут структур – конечно же она там C-совместимая – и определения наследования. Однако не всегда. Исключения позволяются при виртуальном наследовании и если потомок "вдруг" становится полиморфным. Также из описания объектной модели (не путать с описанием модели ООП!) следует ещё одна возможность исключения, когда базовые классы имеют "нулевой" размер.

                    Добавлено
                    Цитата MyNameIsIgor @
                    В любом случае я хочу, чтобы слушающий обладал достаточным интеллектом, чтобы понять сказанное.
                    Лично я в этой фразе
                    Цитата MyNameIsIgor @
                    Ага, тем, у которых всё никак не увеличивается размер, запретили SFINAE.
                    даже не во всех словах разобрался, так что смысл фразы расплылся где-то на километр. Куда уж мне с тобой спорить было бы.
                      Цитата applegame @
                      В смысле не впихнешь?
                      Ну в примере кода ты объявляешь структуру Data с ignored внутри. Если дата уже где-то определена, то так не получится?

                      Цитата applegame @
                      Решаются также, как конфликты имен типов.
                      То есть UDA честно в неймспейсы попадают?

                      Вот, кстати, в расте тут с макросами "немного" коряво - на них неймспейсы не работают. Правда они импортируются явно, но переименовать, вроде, нельзя.
                        Цитата DarkEld3r @
                        Кстати, ещё один вопрос - в С++ ведь нельзя шаблонным параметрам-функциям нормально ограничить сигнатуру.
                        Я тут кстати подумал, а кто не даёт-то? Выбирай костыль:
                        ExpandedWrap disabled
                          template <typename T> struct check;
                          template <>           struct check<int(int)>{};
                           
                          template <typename T>
                          struct impl : check<T>
                          {
                            static void doIt(T *t) { /* ... */ }
                          };
                           
                          template <typename T>
                          void f(T *t)
                          {
                            return impl<T>::doIt(t);
                          }
                        Чуть проще.
                        ExpandedWrap disabled
                          template <typename T> struct check;
                          template <>           struct check<int(int)>{};
                           
                          template <typename T>
                          void f(T *t)
                          {
                            check<T>();
                            /* ... */
                          }
                        Ну или совсем элементарно.
                        ExpandedWrap disabled
                          template <int (*t)(int)>
                          void f()
                          {
                            /* ... */
                          }
                        Зачем ради сахара тащить SFINAE?
                          Qraizer, думаю, что имеются в виду любые объекты-функции.
                            Цитата Qraizer @
                            Выбирай костыль:
                            Так вот именно, что костыль. :)

                            Я ж не утверждал, что сделать нельзя и тем более того, что оно часто/сильно надо. Просто в расте синтаксически оно практически одинаково. Как аналог std::function для нешаблонных функций, так и дженерики.
                              Тогда ждём концептов, которые дадут нам явные трейты вместо утиных. А до тех пор -- костылить их руками.
                                Цитата DarkEld3r @
                                Цитата Qraizer @
                                Выбирай костыль:
                                Так вот именно, что костыль. :)

                                Я ж не утверждал, что сделать нельзя и тем более того, что оно часто/сильно надо. Просто в расте синтаксически оно практически одинаково. Как аналог std::function для нешаблонных функций, так и дженерики.

                                А эти костыли точно делают то, что ты хотел?
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (33) « Первая ... 8 9 [10] 11 12 ...  32 33


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0672 ]   [ 15 queries used ]   [ Generated: 18.07.25, 21:38 GMT ]