Delphi vs C++ vs C#
, ну и Java немножко, где-то ближе к старшему байту номеров страниц
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
| ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
| [216.73.216.192] |
|
|
Правила раздела:
| Страницы: (495) « Первая ... 425 426 [427] 428 429 ... 494 495 ( Перейти к последнему сообщению ) |
Delphi vs C++ vs C#
, ну и Java немножко, где-то ближе к старшему байту номеров страниц
|
Сообщ.
#6391
,
|
|
|
|
Цитата korvin @ Цитата D_KEY @ Это было понятно(см. выше я где-то это же самое говорил кому-то). Но профит тут исключительно теоретический. Это все равно, что заявлять, что от статической типизации профит исключительно теоретический. Или, что от вывода типов профит исключительно теоретический. Или от шаблонов/дженериков. Или от контрактов. Нет, не все равно В одном случае имеем практическую пользу, а в другом нет.Но спорить можно бесконечно, однако "разница между теорией и практикой в том, что в теории разницы между ними нет, а на практике она присутствует"(не помню кто и за точность не ручаюсь). Цитата В каком месте тут надежней/проще/полезней и даже ошибиться гораздо сложнее? Меньше кода, может использоваться любой контейнер с нужными характеристиками и пр. Цитата Как теперь будет выглядеть функция scalarProduct для vector<int>? Как обычная функция, работающая с vector<int> Да, она сможет принять вектора разных длин, но этого можно избежать тривиальной проверкой на равенство размеров.Кроме того, если ты в Haskell будешь получать вектора из разных источников(а так и будет на практике), ты все-равно не сможешь ничего гарантировать. Но может не стоит вдаваться в спор по поводу полезности? Пример-то все-равно интересный Добавлено Цитата korvin @ Потому что инстансы тайпклассов диспетчеризуются по типам, для того, чтобы на каждой "итерации" правильно выбирать реализацию scalarProduct, тип списка должен построиться полностью. Так инстанс же будет один на один параметризованный тип. Добавлено А толк будет на практике только в сочетании с: Цитата Максимум, что он может -- потребовать проверку в сомнительных случаях и уже после проверки считать, что равенство/неравенство длин доказано. Добавлено Цитата D_KEY @ А толк будет на практике только в сочетании с: Цитата Максимум, что он может -- потребовать проверку в сомнительных случаях и уже после проверки считать, что равенство/неравенство длин доказано. Кстати, кто-нибудь знает, можно ли этого добиться в Kotlin применительно к данному примеру? |
|
Сообщ.
#6392
,
|
|
|
|
Цитата D_KEY @ Нет, не все равно В одном случае имеем практическую пользу, а в другом нет.Но спорить можно бесконечно, однако "разница между теорией и практикой в том, что в теории разницы между ними нет, а на практике она присутствует"(не помню кто и за точность не ручаюсь). Отлично, теперь у нас возможность повысить количество выявляемых в компайл-тайме ошибок не является практически полезной, ок. Цитата D_KEY @ Меньше кода, может использоваться любой контейнер с нужными характеристиками и пр. "надежней/проще/полезней и даже ошибиться гораздо сложнее" состоит в прямой зависимости от этих качеств? Цитата D_KEY @ Как обычная функция, работающая с vector<int> Да, она сможет принять вектора разных длин, но этого можно избежать тривиальной проверкой на равенство размеров.Потом тривиально проверкой на равенство размеров матриц, потом еще и еще, при чем, если проверку впихнуть в саму scalarProduct, то использовать ее в циклах станет чуть менее эффективно, и тогда мы напишем scalarProduct_unsafe и пошло-поехало. Цитата D_KEY @ Кроме того, если ты в Haskell будешь получать вектора из разных источников(а так и будет на практике), ты все-равно не сможешь ничего гарантировать. Естественно, поэтому нужно идти дальше, к MLTT. Цитата D_KEY @ Так инстанс же будет один на один параметризованный тип. Дык у нас как бы два типа: Cons<a> и Nil вообще-то. Иначе и надобности в тайпклассах не было бы. Добавлено Цитата D_KEY @ Кроме того, если ты в Haskell будешь получать вектора из разных источников(а так и будет на практике), ты все-равно не сможешь ничего гарантировать. Кстати нужно будет просто реализовать приведение этих векторов к одному типу (к одной длине). Добавлено Цитата korvin @ Дык у нас как бы два типа: Cons<a> и Nil вообще-то. Иначе и надобности в тайпклассах не было бы. Где a в данном случае не тип элементов, а тип хвоста. |
|
Сообщ.
#6393
,
|
|
|
|
Цитата korvin @ Отлично, теперь у нас возможность повысить количество выявляемых в компайл-тайме ошибок не является практически полезной, ок. Ты не понял. Я к тому, что в реальной ситуации у тебя скорее всего не будет возможности такой проверкой воспользоваться. Цитата Потом тривиально проверкой на равенство размеров матриц, потом еще и еще, при чем, если проверку впихнуть в саму scalarProduct, то использовать ее в циклах станет чуть менее эффективно, и тогда мы напишем scalarProduct_unsafe и пошло-поехало. Не помню случая, чтобы проверка размера вектора хоть сколько-нибудь существенно сказывалась на производительности Цитата Естественно, поэтому нужно идти дальше, к MLTT. Ну вот когда пойдем, тогда и поговорим Ладно, давай лучше дальше про пример. Цитата Цитата D_KEY @ Так инстанс же будет один на один параметризованный тип. Дык у нас как бы два типа: Cons<a> и Nil вообще-то. Иначе и надобности в тайпклассах не было бы. Я видел. Пока не вижу противоречий с тем, что я написал. Добавлено Смотри. У ScalarProduct будет описано два инстанса. Один для Nil, другой через тайпклассу, который приведет к двум инстансам для Cons<Nil> и для Cons<Cons<T>>, остальные не нужны, потому никакого генерирования типов во время выполнения не будет. |
|
Сообщ.
#6394
,
|
|
|
|
Цитата D_KEY @ Ты не понял. Я к тому, что в реальной ситуации у тебя скорее всего не будет возможности такой проверкой воспользоваться. любой вызов scalarProduct -- уже использование этой проверки. Цитата D_KEY @ Не помню случая, чтобы проверка размера вектора хоть сколько-нибудь существенно сказывалась на производительности ![]() Абстрагируйся от конкретного примера, контракт может быть сложней. Цитата D_KEY @ Ну вот когда пойдем, тогда и поговорим ![]() Не ну я могу конечно привести код на Agda, но мы и так тут сильно оффтопим =) Цитата D_KEY @ Цитата Цитата D_KEY @ Так инстанс же будет один на один параметризованный тип. Дык у нас как бы два типа: Cons<a> и Nil вообще-то. Иначе и надобности в тайпклассах не было бы. Я видел. Пока не вижу противоречий с тем, что я написал. Смотри. У ScalarProduct будет описано два инстанса. Один для Nil, другой "сгенерированный по тайпклассу", который приведет к двум инстансам для Cons<Nil> и для Cons<Cons<T>>, остальные не нужны, потому никакого генерирования типов во время выполнения не будет. В смысле? У нас два типа, два инстанса, конкретный тип списка напрямую зависит от длины т.о. получаем что для типа ![]() ![]() Cons Integer (Cons Integer (Cons Integer Nil)) функция scalarProduct выполнится четыре раза и каждый раз ей нужно проверять какой тип у выражения (Cons или Nil), чтобы знать какую реализацию выбрать. Причем в рантайме. Не вижу каким образом можно это сделать, не зная тип в рантайме. Цитата D_KEY @ "сгенерированный по тайпклассу", который приведет к двум инстансам для Cons<Nil> и для Cons<Cons<T>> Что эта фраза означает? Нет никаких двух инстансов для Cons<Nil> и Cons<Cons<T>> "сгенерированных по тайпклассу". Есть два инстанса: для Cons и для Nil. |
|
Сообщ.
#6395
,
|
|
|
|
Цитата korvin @ Отлично, теперь у нас возможность повысить количество выявляемых в компайл-тайме ошибок не является практически полезной, ок. Как раз-таки у женериков в Java этих самых проверок гораздо меньше. |
|
Сообщ.
#6396
,
|
|
|
|
Цитата Мяут-Настоящий @ Как раз-таки у женериков в Java этих самых проверок гораздо меньше. А при чем тут дженерики джавы? И в сравнении с чем? List<A> -- это явно больше статических проверок, чем просто List с типом элемента Object Добавлено Цитата korvin @ функция scalarProduct выполнится четыре раза и каждый раз ей нужно проверять какой тип у выражения (Cons или Nil), чтобы знать какую реализацию выбрать. Причем в рантайме. Не вижу каким образом можно это сделать, не зная тип в рантайме. Впрочем пожалуй таки можно, у каждого типа есть определенный конечный набор конструкторов (в нашем случае по одному конструктору на тип), соответственно инстанс тайпкласса может ассоциировать свои функции не только с типом (для статической диспетчеризации), но и с конструкторами типа (для динамической, если она понадобится). Делает ли Хаскелл это на самом деле так -- не знаю. |
|
Сообщ.
#6397
,
|
|
|
|
Цитата korvin @ А при чем тут дженерики джавы? И в сравнении с чем? С шаблонами. Так как List<A> в C++ это совершенно новый тип, а List<A> в Java - это List с автоматическим приведением параметризованного типа T к A там, где это необходимо. |
|
Сообщ.
#6398
,
|
|
|
|
Цитата Мяут-Настоящий @ С шаблонами. Так как List<A> в C++ это совершенно новый тип, а List<A> в Java - это List с автоматическим приведением параметризованного типа T к A там, где это необходимо. Ну мы тут сейчас не совсем дженерики vs шаблоны обсуждаем, точнее не в том ключе, о котором ты говоришь. Мы обсуждаем их в контексте реализации зависимых типов. На чем проще/удобней/надежней/возможно-вообще их реализовать. Игорь, кстати, обещал что-то изобразить на шаблонах, у D_KEY'я есть идея про общий абстрактный класс. Может они приведут полный код? Делфийский код был, но в пылу дискуссии о практической применимости как-то затерялся, |
|
Сообщ.
#6399
,
|
|
|
|
Цитата korvin @ любой вызов scalarProduct -- уже использование этой проверки. Решил доказать полезность синтетическим примером? Цитата Не ну я могу конечно привести код на Agda, но мы и так тут сильно оффтопим =) Боюсь, что я пока все-равно не готов к этому Цитата У нас два типа, два инстанса, конкретный тип списка напрямую зависит от длины т.о. получаем что для типа ![]() ![]() Cons Integer (Cons Integer (Cons Integer Nil)) функция scalarProduct выполнится четыре раза и каждый раз ей нужно проверять какой тип у выражения (Cons или Nil), чтобы знать какую реализацию выбрать. Причем в рантайме. Не вижу каким образом можно это сделать, не зная тип в рантайме. Нет, не так. Напишу позднее, что происходит(на мой взгляд). Цитата Есть два инстанса: для Cons и для Nil. Мы же вроде говорим о рантайме уже. Добавлено Цитата korvin @ у D_KEY'я есть идея про общий абстрактный класс. Может они приведут полный код? У меня, к сожалению, нет времени даже на то, чтобы объяснить тебе, что не требуется создание типов в рантайме А суть идеи с абстрактными классами в том, что мы на определенном этапе для рекурсии отказываемся от информации о типе(что и происходит в случае дженериков). Это не так красиво... |
|
Сообщ.
#6400
,
|
|
|
|
Цитата korvin @ Игорь, кстати, обещал что-то изобразить на шаблонах Я ничего не обещал - это во-первых. Во-вторых, я в очередной раз убедился, что не могу вести с вами конструктивную дискуссию, так что потерял интерес к этому разговору. |
|
Сообщ.
#6401
,
|
|
|
|
korvin, попробую псевдокодом(так быстрее). Допустим в С++ добавили дженерики(или в C# шаблоны, в общем, получили такую дикую смесь, дженерики обозначаются через [], шаблоны - <>), тогда код на Haskell можно было бы переписать как-то так(для простоты можно считать типы ссылочными, чтобы не думать о всяких * ):
![]() ![]() struct Nil {} struct Cons[a] { Cons(int n, a tail); //... }; template<typename T> struct ScalarProduct; template<> struct ScalarProduct<Nil> { int scalarProduct(Nil, Nil) { return 0; } }; template<typename T> struct ScalarProduct<Cons[T]> { int scalarProduct(Cons[T] a, Cons[T] b) { return n1 * n2 + scalarProduct(a.tail(), b.tail()); } }; template<typename T> int f(int n, int i, T as, T bs) { if (n == 0) { return ScalarProduct<T>::scalarProduct(as, bs); } return f(n-1, i+1, new Cons[T](2*i+1, as), new Cons[T](i*i, bs)); } int g(int n) { return f(n, 0, new Nil(), new Nil()); } Так понятнее, почему Haskell коду не нужно генерировать типы в рантайме? Или таки нужно словами? |
|
Сообщ.
#6402
,
|
|
|
|
Цитата D_KEY @ Решил доказать полезность синтетическим примером? Вычисление скалярного произведения векторов -- синтетический пример? Может быть... Предложи пример по-лучше. Цитата D_KEY @ Цитата Есть два инстанса: для Cons и для Nil. Мы же вроде говорим о рантайме уже. в рантайме нет инстансов тайпклассов, это статическая сущность. |
|
Сообщ.
#6403
,
|
|
|
|
Цитата korvin @ Цитата D_KEY @ Решил доказать полезность синтетическим примером? Вычисление скалярного произведения векторов -- синтетический пример? Может быть... В сочетании с остальным кодом - да. Цитата Цитата D_KEY @ Цитата Есть два инстанса: для Cons и для Nil. Мы же вроде говорим о рантайме уже. в рантайме нет инстансов тайпклассов, это статическая сущность. Я о том, что остается от инстансов в рантайме. Понятно, что в рантайме нет тайпклассов, и даже, собственно, инстансов. Но есть сгенерированный компилятором код |
|
Сообщ.
#6404
,
|
|
|
|
Цитата D_KEY @ korvin, попробую псевдокодом(так быстрее). Допустим в С++ добавили дженерики(или в C# шаблоны, в общем, получили такую дикую смесь, дженерики обозначаются через [], шаблоны - <>), тогда код на Haskell можно было бы переписать как-то так(для простоты можно считать типы ссылочными, чтобы не думать о всяких * ): Так понятнее, почему Haskell коду не нужно генерировать типы в рантайме? Нет, не понятней. Добавлено Цитата D_KEY @ В сочетании с остальным кодом - да. Что значит "в сочетании с остальным кодом"? Моя задача написать функцию scalarProduct, такую что <...>. Я это сделал. Она никак не связана с остальным кодом. Добавлено Цитата D_KEY @ Я о том, что остается от инстансов в рантайме. Понятно, что в рантайме нет тайпклассов, и даже, собственно, инстансов. Но есть сгенерированный компилятором код ![]() Мне в общем-то даже не важно, что там происходит в рантайме, хоть сохранение типов, хоть диспетчеризация по конструкторам, главное, что код работает так как нужно. |
|
Сообщ.
#6405
,
|
|
|
|
Цитата korvin @ Нет, не понятней. А сам псевдокод понял? Будет сгенерирован код для f<Nil> и для f<Cons[a]>, соответственно. В f<Nil> будут созданы объекты Cons[Nil], затем будет вызвана foo<Cons[a]>, а информация о том, что a - это именно Nil - уже будет не нужна, там будут созданы объекты Cons[Cons[a]](на самом деле просто Cons[b]) и т.д. Когда же дойдет дело до ScalarProduct, то будет осуществлено обращение к ScalarProduct<Cons[a]>(или к ScalarProduct<Nil>, если длина нулевая), что приведет к вызову нужной функции, которой не нужно знать является ли a Nil или Cons[b]. Сам ScalarProduct будет инстанцирован два раза: ScalarProduct<Nil> и ScalarProduct<Cons[a]>(ибо ему все-равно, что такое a и продолжение инстанцирования не требуется). Добавлено Цитата korvin @ Моя задача написать функцию scalarProduct, такую что <...>. Я это сделал. Она никак не связана с остальным кодом. Она связана с остальным кодом тем, что ей нельзя воспользоваться в случае списков, полученных из разных мест. А на практике тебе понадобится именно это. |