Oberon space

General Category => Общий раздел => Тема начата: valexey от Февраль 29, 2012, 03:51:22 pm

Название: Что не может C++ на этапе компиляции.
Отправлено: valexey от Февраль 29, 2012, 03:51:22 pm
Наткнулся в интернетах на демонстрацию немощности "обобщенки"/параметрического полиморфизма плюсов. Конкретно - оно не позволяет например решить такую задачку: есть два массива (списка, вектора - не важно) неизвестной на этапе компиляции длины. Нужно убедиться (на этапе компиляции) что они будут таки обязательно одинаковой длины. То есть что при создании (для простоты задачи, пусть длина указывается только при создании, затем изменять длину нельзя) им передали одно и то же число.

В шарпе это сделать можно, вроде как даже в жабе можно, а вот в плюсах нельзя. Позор.

Оригинальная постановка задачи (возможно более корректная чем у меня) и решение на Haskell'e тут (http://www.linux.org.ru/forum/development/4300872).
Решение на C# и попытка решение на C++ тут (http://migmit.livejournal.com/32688.html).
Название: Re: Что не может C++ на этапе компиляции.
Отправлено: valexey от Февраль 29, 2012, 03:52:53 pm
Для нетерпеливых и самоуверенных приведу сразу решения на хаскелле и шарпе:

Haskell:
module Test where
data Nil = Nil
data Cons a = Cons Integer a
class ScalarProduct a where scalarProduct :: a -> a -> Integer
instance ScalarProduct Nil where scalarProduct Nil Nil = 0
instance ScalarProduct a => ScalarProduct (Cons a) where scalarProduct (Cons n1 a1) (Cons n2 a2) = n1 * n2 + scalarProduct a1 a2
main :: Integer -> Integer
main n = main' n 0 Nil Nil where
  main' :: ScalarProduct a => Integer -> Integer -> a -> a -> Integer
  main' 0 _ as bs = scalarProduct as bs
  main' n i as bs = main' (n-1) (i+1) (Cons (2*i+1) as) (Cons (i^2) bs)

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));
  }
}
Название: Re: Что не может C++ на этапе компиляции.
Отправлено: vlad от Февраль 29, 2012, 04:02:08 pm
Наткнулся в интернетах на демонстрацию немощности "обобщенки"/параметрического полиморфизма плюсов.

Казалось бы - причем тут оберон? :) Хотелось бы хотя бы одного примера практического использования подобного достижения...
Название: Re: Что не может C++ на этапе компиляции.
Отправлено: valexey от Февраль 29, 2012, 04:10:24 pm
Наткнулся в интернетах на демонстрацию немощности "обобщенки"/параметрического полиморфизма плюсов.

Казалось бы - причем тут оберон? :) Хотелось бы хотя бы одного примера практического использования подобного достижения...
Есть некий Сергей Зефиров, у него блог весь в практических использований подобных достижений. Собственно он это все в продакшине пользует :-) Продакшн у него специфический, но тем не менее. Блог его тут: http://thesz.livejournal.com/

А вот тут его статья про всякое подобное и практическое применение оного подобного: http://fprog.ru/2010/issue5/serguey-zefirov-et-al-error-economy/

PS. Оберон тут при том, что иногда смотришь на С++ и думаешь, а не слишком ли он прост и примитивен? Любопытно посмотреть на плюсы как частенько некоторые (в том числе и я) смотрим на Оберон.

PPS. Вообще, хочется подумать, нельзя ли подобные вещи делать как-то проще и привычней нежели в том же Хаскеле, или в шарпах.
Название: Re: Что не может C++ на этапе компиляции.
Отправлено: Geniepro от Март 01, 2012, 06:25:04 am
В паскале было элементарно:
"array[10] of integer" и "array[10] of integer" -- один тип
"array[10] of integer" и "array[11] of integer" -- разные типы...


Название: Re: Что не может C++ на этапе компиляции.
Отправлено: valexey от Март 01, 2012, 08:36:53 am
В паскале было элементарно:
"array[10] of integer" и "array[10] of integer" -- один тип
"array[10] of integer" и "array[11] of integer" -- разные типы...
А какое отношение это имеет к обсуждаемой проблеме?
Название: Re: Что не может C++ на этапе компиляции.
Отправлено: Peter Almazov от Март 01, 2012, 09:22:10 am
Не силен в данной теме, но если раскомментировать строку, которая "// Doesn't work", то сообщение об ошибке выглядит так:
"The type arguments for method '_Test._main<A>(int, int, A, A)' cannot be inferred from the usage. Try specifying the type arguments explicitly."
То есть речь идет о выводе типов.
Я не знаю, декларируется ли в С++ вывод типов. Кто знает, напишите.
Название: Re: Что не может C++ на этапе компиляции.
Отправлено: vlad от Март 01, 2012, 02:12:58 pm
Не силен в данной теме, но если раскомментировать строку, которая "// Doesn't work", то сообщение об ошибке выглядит так:
"The type arguments for method '_Test._main<A>(int, int, A, A)' cannot be inferred from the usage. Try specifying the type arguments explicitly."
То есть речь идет о выводе типов.
Я не знаю, декларируется ли в С++ вывод типов. Кто знает, напишите.

1. Вычисление типов в С++ есть (через одно место, но тем не менее).
2. Твой пример некорректен, потому что речь идет о неизвестной на этапе компиляции длине.
Название: Re: Что не может C++ на этапе компиляции.
Отправлено: valexey от Март 01, 2012, 02:15:49 pm
Не силен в данной теме, но если раскомментировать строку, которая "// Doesn't work", то сообщение об ошибке выглядит так:
"The type arguments for method '_Test._main<A>(int, int, A, A)' cannot be inferred from the usage. Try specifying the type arguments explicitly."
...
2. Твой пример некорректен, потому что речь идет о неизвестной на этапе компиляции длине.
Это ж не пример, а ровно то что слуается когда в этот шарповый код попытаешься засунуть два вектора разной (но не известной на этапе компиляции) длины. То есть тут все правильно. Ошибка на этапе компиляции.