migmit: (Default)
[personal profile] migmit

Кто-то (увы, не помню кто - напомните?) не так давно предлагал вопрос для интервью соискателям: где в C++ находится параметрический полиморфизм? Правильный ответ был "в районе шаблонов". Соответственно, я бы предложил следующий вопрос: а почему шаблоны таки не являются параметрическим полиморфизмом? Правильный ответ: потому что это всего лишь макросы на стероидах. Реализация метапрограммирования. А метапрограммирование ничего не может сделать, если под ним находится слишком слабенькая система.

Вот в чём сие выражается. Я запостил на ЛОР задачку (сопроводив её кодом на Хаскеле): подсчитать скалярное произведение двух векторов, статически гарантировав, что они имеют одинаковую длину. Мне не интересно сейчас снова демонстрировать, как это делается на Хаскеле (очень просто), но даже на C# вот такой код вполне работает:


using System;
interface ScalarProduct<A> {
  int scalarProduct(A second);
}
class Nil : ScalarProduct<Nil> {
  public Nil(){}
  public int scalarProduct(Nil second) {
    return 0;
  }
}
class Cons<A> : ScalarProduct<Cons<A>> where A : ScalarProduct<A> {
  public int value;
  public A tail;
  public Cons(int _value, A _tail) {
    value = _value;
    tail = _tail;
  }
  public int scalarProduct(Cons<A> second){
    return value * second.value + tail.scalarProduct(second.tail);
  }
}
class _Test{
  public static int main(int n){
    return _main(n, 0, new Nil(), new Nil());
  }
  public static int _main<A>(int n, int i, A first, A second) where A : ScalarProduct<A> {
    if (n == 0) {
      return first.scalarProduct(second);
    } else {
      return _main(n-1, i+1, new Cons<A>(2*i+1,first), new Cons<A>(i*i, second)); // Works
      //return _main(n-1, i+1, first, new Cons<A>(i*i, second)); // Doesn't work
    }
  }
}
public class Test{
  public static void Main(){
    Console.Write("Enter a number: ");
    int val = Convert.ToInt32(Console.ReadLine());
    Console.WriteLine(_Test.main(val));
  }
}
Однако, переписав этот код почти один в один на C++ (с шаблонами вместо дженериков), получаем... нерабочий код:

#include <iostream>
template <class A> class ScalarProduct {
public:
  virtual int scalarProduct(const A &second) const = 0;
};
class Nil : public ScalarProduct<Nil> {
public:
  Nil(){}
  virtual int scalarProduct(const Nil &second) const {
    return 0;
  }
};
template <class A> class Cons : public ScalarProduct<Cons<A> > {
public:
  int value;
  const A &tail;
  Cons(int _value, const A &_tail) : value(_value), tail(_tail) {}
  virtual int scalarProduct(const Cons<A> &second) const {
    return value * second.value + tail.scalarProduct(second.tail);
  }
};
class _Test {
public:
  static int main(int n){
    return _main<Nil>(n, 0, Nil(), Nil());
  }
  template <class A> static int _main(int n, int i, const A &first, const A &second){
        if (n == 0) {
            return first.scalarProduct(second);
        } else {
          return _main(n-1, i+1, Cons<A>(2*i+1,first), Cons<A>(i*i, second)); // Doesn't work
          //return _main(n-1, i+1, Cons<Nil>(2*i+1, Nil()), Cons<Nil>(i*i, Nil())); // Works, but isn't what we want
        }
    }
};
int main(int argc, char* argv[]){
  std::cout << "Enter a number: ";
  int val;
  std::cin >> val;
  std::cout << _Test::main(val) << std::endl;
  return 0;
}
Бесконечное развёртывание шаблонов.

Джавский вариант тоже, разумеется, работает.

Originally posted on migmit.vox.com

Date: 2009-12-07 06:05 am (UTC)
From: [identity profile] migmit.vox.com (from livejournal.com)
Во-1, порядок был обратный (сначала была написана плюсовая версия, потом жабская, потом шарповая).

Во-2, да, пост рассчитан на то, что понимание понятия "параметрический полиморфизм" у читателей совпадает с моим. Если ваше - не совпадает, то предьявить собственное определение должны ВЫ.

В-3, покажите мне хоть один ЖЖ-пост, где определены все используемые понятия.

Date: 2009-12-07 06:10 am (UTC)
From: [identity profile] nponeccop.livejournal.com
> В-3, покажите мне хоть один ЖЖ-пост, где определены все используемые понятия.

Это ж мой главный аргумент - что все эти тёрки в ЖЖ о том, чей полиморфизм круче, не имеют научного смысла, т.к. за неимением общепринятого определения отсутствует предмет обсуждения.

Date: 2009-12-07 06:27 am (UTC)
From: [identity profile] migmit.vox.com (from livejournal.com)
И только-то? Вы могли не трудиться, излагая подобный трюизм. Я не считаю ЖЖ научным журналом и не считаю себя обязанным соблюдать научную строгость при публикации.

Date: 2009-12-07 06:44 am (UTC)
From: [identity profile] nponeccop.livejournal.com
Я же как раз и спрашивал, понимаете ли вы, что с научной т.з. ваш пост - фантазия, или нет. Вы ответили - понимаете. Вопрос закрыт.

Date: 2009-12-07 06:53 am (UTC)
From: [identity profile] migmit.vox.com (from livejournal.com)
Гм. Чисто гипотетически - если я зайду к вам в журнал, ткну в произвольный пост и спрошу то же самое, вы сочтёте меня адекватным человеком?

Date: 2009-12-07 02:44 pm (UTC)
From: [identity profile] nponeccop.livejournal.com
Да. Более чем адекватным.

Date: 2009-12-07 06:41 am (UTC)
From: [identity profile] nponeccop.livejournal.com
> Если ваше - не совпадает, то предьявить собственное определение должны ВЫ.

Вообще-то никто никому ничего не должен. Я не говорил, что вы мне что-то должны.

Во-первых, как я могу понять, что моё определение не совпадает с вашим? Хорошо, если размышляя, используя свое определение, я приду к противоречию, и пойму, что что-то не так. А если не приду? Тогда возникнет тихое недопонимание, и я, возможно, заражусь от вас ложными убеждениями.

Соответственно, упоминание используемых определений полезно скажется на качестве вашего ЖЖ. Разумеется, по умолчанию подразумевается, что вы используете общепринятые термины, и ничего пояснять не надо. Но в данном конкретном случае общепринятого определения нет, и пояснения были бы полезны.

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

В-третьих, мне было интересно вас подколоть, такой микротроллизм. Извините, если излишней эмоциональностью комментария и нарочитой гиперболизированностью вас задело.

Date: 2009-12-07 06:52 am (UTC)
From: [identity profile] migmit.vox.com (from livejournal.com)
> Хорошо, если размышляя, используя свое определение, я приду к противоречию, и пойму, что что-то не так. А если не приду? Тогда возникнет тихое недопонимание, и я, возможно, заражусь от вас ложными убеждениями.

В математике, например, это происходит сплошь и рядом, если речь идёт о таких областях, где понятия ещё не до конца устаканились. Да и в основах тоже: в одних статьях, например, ноль считают натуральным числом, в других нет. И как-то все понимают.

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

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

> мне было интересно вас подколоть, такой микротроллизм

Рискуете. Я умею обращаться с банхаммером.

Date: 2009-12-07 02:44 pm (UTC)
From: [identity profile] nponeccop.livejournal.com
> Рискуете.

Учту.

Date: 2009-12-07 02:58 pm (UTC)
From: [identity profile] nponeccop.livejournal.com
> если речь идёт о таких областях, где понятия ещё не до конца устаканились

В статьях - вряд ли. Если понятия не устаканились - это лишь означает, что каждый волен выдумать собственные определения и указать их, но не то, что можно использовать не устаканившиеся понятия без определений.

> в одних статьях, например, ноль считают натуральным числом,
> в других нет. И как-то все понимают

Но указывают ведь - считают или не считают. И если не указывают - то это либо понятно из контекста, либо не имеет для понимания статьи ключевого значения (совершенно понятно, что полукольца (N,+) с нулем и с единицей одинаковы с точностью до изоморфизма). И я слабо представляю, чтобы об этом умалчивалось в статье, где это важно.

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

Date: 2009-12-07 03:13 pm (UTC)
From: [identity profile] migmit.vox.com (from livejournal.com)
> Но указывают ведь - считают или не считают.

Отнюдь не всегда.

> И если не указывают - то это либо понятно из контекста,

Несомненно. И если моё - не высказанное явно - понимание ПП отличается от вашего, то, я полагаю, из контекста это должно быть понятно.

> А целое определение, в отличие от факта "да/нет", из контекста уже не вытянешь.

ЖЖ, и блоги вообще, обладают одним чрезвычайно важным отличием от обычных публикаций, даже электронных. Знаете, каким?

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

А это я вообще не собираюсь определять. В данном случае мы имеем дело не с суждением вида "да/нет", а с оценкой. Кому-то уровень Хаскеля покажется запредельным, кому-то и Эпиграммы будет мало.

Date: 2009-12-07 03:52 pm (UTC)
From: [identity profile] nponeccop.livejournal.com
Вы так говорите, как будто я имею к вам какие-то претензии и чем-то недоволен.

Я понял ваш пост так, как будто вы настаивали, что из вашего поста неопровержимо следует, что в С++ нет параметрического полиморфизма.

Если бы это было так, то можно было бы утверждение оспаривать. А раз научного утверждения нет, а есть только субъективная оценка, основанная на интуитивном "понимании" - то и оспаривать нечего.

Date: 2009-12-07 06:04 pm (UTC)
From: [identity profile] migmit.vox.com (from livejournal.com)
> Я понял ваш пост так, как будто вы настаивали, что из вашего поста неопровержимо следует, что в С++ нет параметрического полиморфизма.

Кстати, да: я настаиваю, что параметрического полиморфизма, КАК ЭТО ВЫРАЖЕНИЕ ПОНИМАЮ Я, в C++ нет. И это, пусть не доказывается, но обосновывается именно этим постом. Причём очень похоже, что я не одинок в своём понимании.

Date: 2009-12-07 03:58 pm (UTC)
From: [identity profile] nponeccop.livejournal.com
> И если моё - не высказанное явно - понимание ПП отличается
> от вашего, то, я полагаю, из контекста это должно быть понятно.

Я же сказал уже выше, что если мое понимание отличается от вашего, но я не смогу быстро отыскать противоречий, то из контекста я ничего не вытяну. Поиск противоречий - единственный объективный способ проверять отличия, и он недостаточно эффективен в плане алгоритмической сложности, поэтому шансов непонять - много.

Date: 2009-12-07 03:59 pm (UTC)
From: [identity profile] migmit.vox.com (from livejournal.com)
Ну, звиняйте, буду статью писать - определю всё, что надо, БП.