LINUX.ORG.RU

Типизация : статика против динамики


0

0

Доброе время суток

Ещё один вопрос более общего характера. Насколько мне известно, в, скажем, CL и Erlang используется динамическая типизация; в том же Haskell - статическая, с выведением типов, основанным на модели типизации Хиндли-Милнера; во многих языках применяется статическая типизация без выведения типов. Прошу высказать личные (но желательно аргументированные) мнения о преимуществах/недостатках подходов

★★★★★
Ответ на: комментарий от cvv

>GObject рулеззз!!!

обоснуйте (с)

jtootf ★★★★★
() автор топика

Очевидно, что статическая типизация проще в реализации и надежнее, т.к. не надо таскать с объектом текущий дескриптор типа. И проверка типов может и должна выполняться во время трансляции. Однако у динамической типизации есть большой плюс - гибкость. Например, возможность написать функцию, которая принимает параметры любого типа. В языках со статической типизацией небходимо будет использовать либо механизм шаблонов (C++, Java), либо бестиповые указатели (С), что не очень удобно. Однако, подобное удобство усложняет реализацию и требует дополнительных накладных расходов на уточнение динамического типа и обновление дескрипторов. Такой, подход делает почти невозможным реализацию ЯП с динамической типизацией в виде чистого транслятора.

parser ★★
()
Ответ на: комментарий от parser

>Очевидно, что статическая типизация проще в реализации и надежнее

прошу аргументации. в Tcl, например, "всё есть строка" - где здесь сложность реализации ?

>Например, возможность написать функцию, которая принимает параметры любого типа. В языках со статической типизацией небходимо будет использовать либо механизм шаблонов (C++, Java), либо бестиповые указатели (С), что не очень удобно

Haskell - пример языка со статической типизацией, поддерживающий полиморфные функции (более гибкие, чем те же шаблоны C++); в том же C++ шаблоны функций поддерживают механизм выведения типа - в чём в данном случае будет проявлятся неудобство ?

>Такой, подход делает почти невозможным реализацию ЯП с динамической типизацией в виде чистого транслятора

а что есть не-чистый транслятор ?

jtootf ★★★★★
() автор топика
Ответ на: комментарий от parser

>Например, возможность написать функцию, которая принимает параметры любого типа. В языках со статической типизацией небходимо будет использовать либо механизм шаблонов (C++, Java), либо бестиповые указатели (С)

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

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

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

tche
()

Вот например, встретив на лоре такой код, http://www.linux.org.ru/view-message.jsp?msgid=1891579#1891629 я, естестсенно, немедленно захотел его запустить. Да вот беда, автор забыл написать конструктор для penis. Пришлось медитировать над исходниками функции enlarge, а это неприятно. Было бы лучше, если бы функция сама сообщала тип своего аргумента, выводя его по хиндли милнеру.

ugoday ★★★★★
()
Ответ на: комментарий от jtootf

Я имею в виду гибридную схему. Когда сначала производится трансляция в промежуточное представление, а потом его интерпритация.

parser ★★
()
Ответ на: комментарий от parser

> статическая типизация проще в реализации

Неверно. Отложить "до выяснения", т.е., до рантайма, проще, чем решать здесь и сейчас.

> и надежнее

Это верно.

> Например, возможность написать функцию, которая принимает параметры любого типа.

Функция id в статически-типизированном хаскеле принимает аргументы любого типа. Правда, это единственная такая функция (а что, есть другие сколько-нибудь вменяемые функции с ЛЮБЫМ типом аргументов?).

> небходимо будет использовать либо механизм шаблонов (C++, Java), либо бестиповые указатели (С)

Выучи хотя бы то, что упомянуто в начале топика.

> Такой, подход делает почти невозможным реализацию ЯП с динамической типизацией в виде чистого транслятора.

Не очень понял. Хочешь сказать, компиляторы коммон-лиспа мне снятся?

Miguel ★★★★★
()
Ответ на: комментарий от Miguel

Я хочу сказать, что реализация динамической типизации на языке ассемблера крайне сложна, увеличивает код и требует поддержки средой выполнения.

parser ★★
()
Ответ на: комментарий от parser

>Я имею в виду гибридную схему. Когда сначала производится трансляция в промежуточное представление, а потом его интерпритация.

примеры ?

jtootf ★★★★★
() автор топика
Ответ на: комментарий от Miguel

>Функция id в статически-типизированном хаскеле принимает аргументы любого типа. Правда, это единственная такая функция (а что, есть другие сколько-нибудь вменяемые функции с ЛЮБЫМ типом аргументов?).

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

jtootf ★★★★★
() автор топика
Ответ на: комментарий от Sectoid

>Старая жаба (до JIT).

и при чём здесь динамическая типизация ? или Java когда-то была динамически типизированным языком ?

jtootf ★★★★★
() автор топика
Ответ на: комментарий от jtootf

>и при чём здесь динамическая типизация ? или Java когда-то была динамически типизированным языком ?

Нет.=) Не был. Мой пост был лишь примером "...трансляции в промежуточное представление, а потом его интерпритации...", не более.

Эх, оффтоплю я...

Sectoid ★★★★★
()
Ответ на: комментарий от parser

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

Ты хоть один компилятор динамического языка в жизни писал?

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

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

tche
()
Ответ на: комментарий от tche

>Типы данных проверяются по факту попытки их использовать в какой-либо функции, за счет увеличения кода этой самой функции (диспетчеризация по тэгу).

согласен

>Единственная правильная мысль -- "увеличивает код", ибо к данным приходится цеплять тэги для идентификации их типа

не согласен. контрпример - интерпретатор Tcl. тип любого выражения считается строчным до использования, либо (с версии tclsh >= 8.0), до момента когда в целях оптимизации есть смысл (и возможность) к конктретному типу строку привести. т.е. по крайней мере не везде так

jtootf ★★★★★
() автор топика
Ответ на: комментарий от parser

>>примеры?

>Perl, Python, ранние версии Java

в таком случае прошу пояснения, каким образом промежуточное представление связано именно с наличием динамической типизации - ибо неочевидно

jtootf ★★★★★
() автор топика
Ответ на: комментарий от jtootf

Под тэгом понимается любой способ "транспортировать" информацию о типе данных вместе с самими данными в рантайме. Представление данных в виде строк не противоречит такой модели, до тех пор пока позволяет однозначно идентифицировать тип при необходимости. Например, по строке "1" я могу однозначно сказать, что в ней закодировано целое число.

tche
()
Ответ на: комментарий от tche

>Под тэгом понимается любой способ "транспортировать" информацию о типе данных вместе с самими данными в рантайме. Представление данных в виде строк не противоречит такой модели, до тех пор пока позволяет однозначно идентифицировать тип при необходимости. Например, по строке "1" я могу однозначно сказать, что в ней закодировано целое число.

ок, принято, возражений нет

jtootf ★★★★★
() автор топика
Ответ на: комментарий от jtootf

> в таком случае прошу пояснения, каким образом промежуточное представление связано именно с наличием динамической типизации - ибо неочевидно

А я и не говорил, что они связаны. Я говорил, что динамическая типизация связана с интерпретацией. Читай внимательней.

parser ★★
()
Ответ на: комментарий от parser

Не понял. Кто-то пишет компиляторы на ассемблере???

Miguel ★★★★★
()
Ответ на: комментарий от jtootf

Я, конечно, погорячился. Имелось в виду, что id - единственная функция типа a -> a. Классы типов - другая песня, тут тип будет уже (MyClass a) => a -> a. Дофига функций, скажем, типа a -> Int, правда, все константные.

Miguel ★★★★★
()

>мнения о преимуществах/недостатках подходов

Единственный способ понять это -- написать пару не слишком тривиальных программ в Haskell/МL и в CL/Scheme/Erlang. Все сразу станет ясно. Если вкратце, то динамическая предоставляет больше свободы, поскольку вся проверка типов, выполняется программистом. Но это не значит, что типизация Хиндли-Милнера плоха, она во многих случаях может быть также удобна как и динамическая, в отличие от примитивной статической (как в С,C++,Java).

anonymous
()
Ответ на: комментарий от anonymous

>Единственный способ понять это -- написать пару не слишком тривиальных программ в Haskell/МL и в CL/Scheme/Erlang. Все сразу станет ясно

я несколькими постами раньше задавал уже подобный вопрос, несколько повторюсь : какие, например, задачи для этого бы подошли ?

jtootf ★★★★★
() автор топика
Ответ на: комментарий от parser

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

>>а что есть не-чистый транслятор ?

>Я имею в виду гибридную схему. Когда сначала производится трансляция в промежуточное представление, а потом его интерпритация

>>примеры ?

>Perl, Python, ранние версии Java

>>в таком случае прошу пояснения, каким образом промежуточное представление связано именно с наличием динамической типизации - ибо неочевидно

>А я и не говорил, что они связаны. Я говорил, что динамическая типизация связана с интерпретацией. Читай внимательней.

мне кажется, или мсье ошибается ? динамика не даёт сделать чистый транслятор, не-чистый - это с промежуточным представлением, вроде Perl, Python, ранней Java. так ? про интерпретацию ничего не вижу. что я прочитал невнимательно ?

jtootf ★★★★★
() автор топика
Ответ на: комментарий от jtootf

>какие, например, задачи для этого бы подошли ?

Любые, которые тебе больше нравятся :). А если серьезно, мне не нравятся всякие искуственно поставленные задачи, призванные демонстрировать слабые или наоборот сильные стороны какого-либо подхода, реальность она многограннее :). Если окажется, что выбранная тобой задача хреново решается при помощи Haskell и более удобно на ассемблере, то ты все равно получишь ценный опыт --- как делать не надо.

anonymous
()
Ответ на: комментарий от jtootf

Cоздавал как-то тему в талксах -- почему меня задолбала динамическая типизация. Тема бестолковая получилось, так, высказался просто. Задолбала она по опыту участия в одном достаточно большом проекте, со значительной долей кода на Scheme (в прототипе). Проект связан с САПР для проектирования печатных плат; впрочем это не особо важно в данном контексте. Основной вывод для меня лично -- на отладку из-за ошибок типизации в рантайме уходит слишком много времени.

Касательно удобства кодирования -- пожалуй, если переписать всё это на ML/Ocaml, будет только лучше. Но к моменту старта проекта полной ясности относительно применимости этих языков не было. Было достаточно хорошее знание Haskell, но его применение как раз сочли нерациональным по ряду причин. С/С++/Java/C# были бы однозначно хуже -- как минимум, код распух бы в несколько раз без какого-либо выигрыша.

tche
()
Ответ на: комментарий от jtootf

>динамика не даёт сделать чистый транслятор

Я так понимаю, тебя волнует скорость исполнения полученного кода.
Тут как-то проскальзывало сравнение скорости примитивного способа
численного интегрирования на Scheme и С. Я приведу результаты 
для Bigloo.
Scheme:
(module foo)
(define eps 1e-7)

(define (mid-point a b)
    (/ (+ a b) 2.0))

(define (int a b f)
      (if (< (abs (- b a)) eps)
                 (* (f (mid-point a b)) (- b a))
                          (+ (int a (mid-point a b) f) (int (mid-point a b) b f))))

(display (int 0. 1. (lambda (x) (* x x))))
(newline)

$ bigloo -O6 -unsafe   -o test-bigloo test-bigloo.scm
$ time ./test-bigloo
0.33333333333333

real    0m0.800s
user    0m0.580s
sys     0m0.010s

Теперь для С:
#include<stdio.h>
#include<math.h>

#define eps 1e-7

double
square (double x)
{
  return x * x;
};

double
integrate (double a, double b, double (*integrand) (double x))
{
  if (fabs (b - a) < eps)
    {
      return integrand ((a + b) / 2.) * (b - a);
    }
  else
    {
      return (integrate (a, (a + b) / 2., integrand) +
              integrate ((a + b) / 2., b, integrand));
    };
}

int
main (void)
{

  printf ("%18.15f\n", integrate (0., 1., square));
  return 0;

}

$ gcc -O2 -o test-c  test-c.c -lm
$ time ./test-c
0.333333333333333

real    0m0.845s
user    0m0.470s
sys     0m0.000s

Я прекрасно понимаю, что этот результат не означает, что
Scheme всегда может быть такой же быстрой как С, но он все же 
показывает, что никакого тормозного промежуточного представления при 
исполнении кода откомпилированного bigloo нет.

anonymous
()
Ответ на: комментарий от anonymous

>>динамика не даёт сделать чистый транслятор

это не моя была фраза, я цитировал :)

>Я прекрасно понимаю, что этот результат не означает, что Scheme всегда может быть такой же быстрой как С, но он все же показывает, что никакого тормозного промежуточного представления при исполнении кода откомпилированного bigloo нет

насчёт производительности - я в принципе могу оценивать некоторые задачи FORTRAN vs C vs (C++ + Blitz++) vs Haskell, и пока что не видел сколько-нибудь серьёзных программ на Haskell, в которых повышение производительности до уровня "от в два раза медленнее до несколько быстрее" по сравнению с C не приводило бы к потере той самой лаконичности и выразительности, которой так хороши ФЯП. касательно же промежуточного представления - опять же, ответ не мне, я с автором данного утверждения не согласен (на рпимере опять же Tcl, в котором отродясь динамическая типизация, а промежуточное представление (если я вообще правильно понял что имелось в виду) появилось только с версии 8.0, причём в результате производительность повысилась, а не наоборот)

jtootf ★★★★★
() автор топика
Ответ на: комментарий от jtootf

>сколько-нибудь серьёзных программ на Haskell, в которых повышение производительности до уровня "от в два раза медленнее до несколько быстрее" по сравнению с C не приводило бы к потере той самой лаконичности и выразительности

Ну дык бесплатный сыр он только в мышеловке :). Cила Haskell в том, что он позволяет (в отличие от С) писать выразительно в тех местах программы, где производительность не особо требуется. Если таких мест в программе немного --- значит Haskell ошибочный выбор. Жесткую числодробильню мне все же нравится писать на С.

anonymous
()
Ответ на: комментарий от jtootf

Промежуточное представление !ИНТЕРПРЕТИРУЕТСЯ!, т.е. это тот же интерпретатор, но он интерпретирует не код на ЯП, а код на языке промежуточного представления. Т.о. динамическая типизация связана не с промежуточным представлением, а с интерпретацией. Об этом я сразу и написал:

> Такой, подход делает почти невозможным реализацию ЯП с динамической типизацией в виде чистого транслятора.

parser ★★
()
Ответ на: комментарий от parser

>Промежуточное представление !ИНТЕРПРЕТИРУЕТСЯ!Т.о. динамическая типизация связана не с промежуточным представлением, а с интерпретацией.

!БРЕД! Динамическая типизация == проверка типа во время исполнения. Допустим я пишу программу на C используя всюду один тип --- void* плюс небольшой набор функций типа схемовских car,cdr,list?,list, конструкторов и базовых операций над целыми числами, которые внутри реализованы с применением других типов а в качестве возвращаемого значения и аргументов имеют void*. Дык вот вся программа,за исключением маленького ядра, получается динамически типизированной. После я ее компилирую С компилятором и получаю бинарник. Внимание вопрос: где в этом бинарнике промежуточное представление и его интерпретатор?

anonymous
()
Ответ на: комментарий от parser

>Прочитай, тред сначала и подумай головой. Только внимательно прочитай.

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

jtootf ★★★★★
() автор топика
Ответ на: комментарий от parser

>Прочитай, тред сначала и подумай головой. Только внимательно прочитай.

Прочитай, прочитай ... Что с твоей точки зрения чистый транслятор? Какая нахрен разница, "чистый" он или "грязный", если он работает, и производит достаточно эффективный код? В качестве примера могу привести Bigloo,Gambit-C и несколько реализаций CL. Эта дискуссия напоминает мне по своей бессмысленности какой-то тред на лоре про "правильные" и "неправильные" (это те, которые переводят скрипт в другое представление и только потом интерпретируют, например perl) интерпретаторы.

anonymous
()
Ответ на: комментарий от parser

>Прочитай, тред сначала и подумай головой. Только внимательно прочитай.

Головой подумать желательно всё же тебе -- анонимус выше привёл замечательный пример, показывающий как превратить С в компилируемый язык с динамической типизацией.

tche
()
Ответ на: комментарий от jtootf

Итак, попробую сформулировать свое мнение максимально кратко:

1) Статическая типизация проста в реализации. Т.к. дескритор типа необходим только во время трансляции.

2) Статическая типизация надежнее. Т.к. типы указываются явно и у компилятора есть больше информации для обнаружения несоответствия типов.

3) Динамическая типизация гибче. Она позволяет писать функции общего назначения, не зависящие от типа фактических параметров.

4) Динамическая типизация менее надежна, т.к. большая часть работы по контролю за несоответствием типов ложится на программиста.

5) Динамическая типизация влечет накладные расходы, связанные с увеличением кода и необходимостью производить пересвязывание памяти для объектов несовместимых по структуре.

Из недостатков динамической типизации следует вывод, что реализовывать ЯП с динамической типизацией легче в виде интерпретатора потому, что:

1) Так устроен механизм динамической типизации. 2) Накладные расходы перекрываются общим временем интерпретации, так что в этой среде динамическое связывание оказывается более дешевым.

P.S. кратко не получилось :)

parser ★★
()
Ответ на: комментарий от anonymous

Я уже писал выше, что, по моему мнению, чистый транслятор. А определение гибридной схемы я дал по просьбе автора. Кстати, гибридная схема была вплетена в топик искусственно и непосредственного отношения к теме треда не имеет.

parser ★★
()
Ответ на: комментарий от parser

> 1) Статическая типизация проста в реализации. Т.к. дескритор типа необходим только во время трансляции.

Это утверждение неверно. Например, алгоритм вывода типов существенно сложнее простого приделывания фигового дескриптора к значению.

> 2) Статическая типизация надежнее. Т.к. типы указываются явно

Первое верно, второе нет. Типы не обязательно указывать явно. Статическая типизация этого, зачастую, не требует.

> 3) Динамическая типизация гибче. Она позволяет писать функции общего назначения, не зависящие от типа фактических параметров.

Это утверждение неверно. См. пример с функцией id, работающей независимо от типа фактического параметра.

> реализовывать ЯП с динамической типизацией легче в виде интерпретатора

Это верно. Равно как и более общее утверждение: любой ЯП реализовывать проще в виде интерпретатора. К динамической типизации это имеет мало отношения.

Miguel ★★★★★
()
Ответ на: комментарий от parser

> 1) Статическая типизация проста в реализации. Т.к. дескритор типа необходим только во время трансляции.

Это неверно - наивная реализация динамической типизации (run-time type checking) не сложнее в реализации, чет таковая же реализация статической (compile-time type checking), независимо от компилируемости/байткодо-/дерево-интерпретируемости языка.

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

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.