Статическая и динамическая типизация

Формальное обоснование

Формальным обоснованием для систем типов служит теория типов. В состав языка программирования включается система типов для осуществления проверки типов или во время выполнения, требующая явного провозглашения типов или выводящая их самостоятельно. Марк Мэнесси (англ. Mark Manasse) сформулировал проблему так:

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

Типизация в стандартизации

Стандартизация охватывает множество смежных технических дисциплин. Благодаря этой науке приборы учета показывают одни и те же значения, рабочие инструменты предназначены для одних и тех же работ, а предлагаемые покупателям товары сертифицируются по одним и тем же параметрам. Типизация – это установление единых правил и норм при производстве тех или иных товаров, орудий труда и прочее. Данный процесс развивается в различных направлениях стандартизации технологий, учитывается при разработке нормативной документации, влияет на стандартные методики расчетов и составления смет.

Статическая и динамическая типизация

сильный против слабого

противоположностью » строго типизированного «является» слабо типизированный», что означает, что вы можете работать с системой типов. C, как известно, слабо типизирован, потому что любой тип указателя преобразуется в любой другой тип указателя просто путем приведения. Паскаль должен был быть строго напечатан, но надзор в дизайне (untagged variant records) ввел лазейку в систему типов, поэтому технически она слабо типизирована.
Примеры действительно строго типизированных языков включают CLU, Standard ML и Haskell. Стандарт ML фактически претерпел несколько изменений, чтобы удалить лазейки в системе типов, которые были обнаружены после того, как язык был широко развернут.

что здесь происходит?

в целом, оказывается, не так уж полезно говорить о » сильных» и «слабый»

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

  • любители часто объединяют их с «статическими»и » динамическими».

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

  • профессионалы не могут договориться о том, что именно означают эти термины.

  • в целом, вы вряд ли информировать или просвещать свою аудиторию.

печальная правда заключается в том, что когда дело доходит до систем типов,»сильный» и «слабый» не имеют общепризнанного технического значения. если вы хотите обсудить относительную прочность типа системы, лучше обсудить, какие именно гарантии предоставляются, а какие нет.
Например, хороший вопрос: «гарантируется ли, что каждое значение данного типа (или класса) было создано путем вызова одного из конструкторов этого типа?- В С ответ-нет. В CLU, F# и Haskell это да. Для C++ я не уверен-я хотел бы знать.

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

на педантичном уровне, нет, потому что слово «сильный» на самом деле ничего не значит. Но на практике люди почти всегда делают одно из двух:—2—>

  • они (неправильно) используют «сильный» и «слабый», чтобы означать «статический» и «динамический», и в этом случае они (неправильно) используют «строго типизированный» и «статически типизированный» взаимозаменяемо.

  • они используют «сильный» и «слабый» для сравнения свойств систем статического типа. Очень редко можно услышать, как кто-то говорит о «сильном» или » слабом» система динамического типа. За исключением FORTH, который на самом деле не имеет никакой системы типов, я не могу думать о динамически типизированном языке, где система типов может быть разрушена. По определению, эти проверки bulit в механизм выполнения, и каждая операция проверяется на здравомыслие перед выполнением.

Статически типизированные языки

Статические языки проверяют типы в программе во время компиляции, еще до запуска программы. Любая программа, в которой типы нарушают правила языка, считается некорректной. Например, большинство статических языков отклонит выражение (язык Си — это исключение из этого правила). Компилятор знает, что «a» — это строка, а 1 — это целое число, и что работает только когда левая и правая часть относятся к одному типу. Так что ему не нужно запускать программу чтобы понять, что существует проблема. Каждое выражение в статически типизированном языке относится к определенному типу, который можно определить без запуска кода.

Многие статически типизированные языки требуют обозначать тип. Функция в Java принимает два целых числа и возвращает третье целое число. Другие статически типизированные языки могут определить тип автоматически. Та же самая функция сложения в Haskell выглядит так: . Мы не сообщаем языку типы, но он может определить их сам, потому что знает, что работает только на числах, так что и должны быть числами, значит функция принимает два числа как аргументы.

Это не уменьшает «статичность» системы типов. Система типов в Haskell знаменита своей статичностью, строгостью и мощностью, и в по всем этим фронтам Haskell опережает Java.

Неявная типизация¶

Язык с неявной типизацией (implicit typing) при объявлении языковых элементов не требует от разработчика указания принадлежности к конкретному типу данных и возлагает определение типов на компилятор или интерпретатор.

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

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

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

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

Именно по этой причине правило именования распространяется и на языки с явной типизацией.

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

К языкам с неявной типизацией относятся такие языки, как JavaScript, PHP и другие.

Эмулируем самую строгую типизацию

Номинальной типизации в TypeScript нет, но мы можем сэмулировать его поведение, сделав любой тип уникальным. Для этого в тип необходимо добавить уникальное свойство. Этот прием упоминается в англоязычных статьях под термином Branding, и вот как это выглядит:

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

Все выглядит неплохо за исключением четырех последних строчек. Для создания идентификаторов понадобится функция-хелпер:

Недостатком этого способа является то, что данная функция останется в рантайме.

Виды типизации

Все языки делятся на типы по четырем признакам:

  • есть ли вообще типизация или язык бестиповый;
  • статистическая она или динамическая;
  • сильная или слабая;
  • явная или неявная.

Пойдемте посмотрим в чем отличия каждого и какие преимущества дает та или иная типизация.

Сначала о бестиповой типизации

Даже если нет типа, язык имеет бестиповую типизацию. Сложно? Сейчас разберемся.

Бестиповая типизация характерна для низкоуровневых или эзотерических языков. Например, Fort или Brainfuck. Главная особенность таких языков – в них все сущности выражаются в последовательности бит с разной длиной.

Преимущества использования бестиповых языков:

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

Недостатки:

слабая абстракция. Это отягчает работу со сложными типами данных.

Статическая и динамическая типизация

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

Статическая и динамическая типизация

Преимущества статической типизации:

  • проверки выполняются один раз. Если ошибки есть, вы о них узнаете сразу на этапе компиляции;
  • скорость выполнения. Языки со статистической типизацией работают быстрее;
  • при поддержке интегрированной среды разработки – сроки разработки сокращаются.

Плюсы динамической типизации:

  • удобно описывать алгоритмы обобщенного типа. Например, легко писать сортировку массивов, она может работать с разными типами данных;
  • легкое освоение. Динамические языки проще учить.

В некоторых статических языках можно использовать динамику:

  • C# – есть псевдотип dynamic;
  • Delphi – использует динамику посредством variant;
  • F# – может имитировать динамическую типизацию через оператора «?».

Примерно так же в динамически типизированных языках можно работать со статикой. Это позволяют делать Common Lisp и Perl.

О слабой и сильной типизации

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

Преимущества strong typing:

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

Преимущества weak typing:

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

Явная и неявная типизация

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

Разнообразие статических систем типизации

Давайте взглянем на два знаменитых примера статически типизированных языков: Go и Haskell. В системе типизации Go нет обобщенных типов, типов с «параметрами» от других типов. Например, можно создать свой тип для списков MyList, который может хранить любые нужные нам данные. Мы хотим иметь возможность создавать MyList целых чисел, MyList строк и так далее, не меняя исходный код MyList. Компилятор должен следить за типизацией: если есть MyList целых чисел, и мы случайно добавляем туда строку, то компилятор должен отклонить программу.

Go специально был спроектирован таким образом, чтобы невозможно было задавать типы вроде MyList. Лучшее, что возможно сделать, это создать MyList «пустых интерфейсов»: MyList может содержать объекты, но компилятор просто не знает их тип. Когда мы достаем объекты из MyList, нам нужно сообщить компилятору их тип. Если мы говорим «Я достаю строку», но в реальности значение — это число, то будет ошибка исполнения, как в случае с динамическими языками.

В Go также нет множества других возможностей, которые присутствуют в современных статически типизированных языках (или даже в некоторых системах 1970-х годов). У создателей Go были свои причины для этих решений, но мнение людей со стороны по этому поводу иногда может звучать резко.

Теперь давайте сравним с Haskell, который обладает очень мощной системой типов. Если задать тип MyList, то тип «списка чисел» это просто . Haskell не даст нам случайно добавить строку в список, и удостоверится, что мы не положим элемент из списка в строковую переменную.

Haskell может выражать намного более сложные идеи напрямую типами. Например, означает «MyList значений, которые относятся к одному типу чисел». Это может быть список integer’ов, float’ов или десятичных чисел с фиксированной точностью, но это определенно никогда не будет списком строк, что проверяется при компиляции.

Можно написать функцию add, которая работает с любыми численными типами. У этой функции будет тип . Это означает:

  • может быть любым численным типом ().
  • Функция принимает два аргумента типа и возвращает тип ().

Последний пример. Если тип функции это , то она принимает строку и возвращает строку. Но если это , то она также совершает какой-то ввод/вывод. Это может быть обращение к диску, к сети, чтение из терминала и так далее.

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

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

Сравните эту мощность с Go, который не способен выразить простую идею MyList, не говоря уже о «функции, которая принимает два аргумента, и они оба численные и одного типа, и которая делает ввод/вывод».

Подход Go упрощает написание инструментов для программирования на Go (в частности, реализация компилятора может быть простой). К тому же, требуется изучить меньше концепций. Как эти преимущества сравнимы со значительными ограничениями — субъективный вопрос. Однако, нельзя поспорить, что Haskell сложнее изучить, чем Go, и что система типов в Haskell намного мощнее, и что Haskell может предотвратить намного больше типов багов при компиляции.

Go и Haskell настолько разные языки, что их группировка в один класс «статических языков» может вводить в заблуждение, не смотря на то, что термин используется корректно. Если сравнивать практические преимущества безопасности, то Go ближе к динамических языкам, нежели к Haskell’у.

С другой стороны, некоторые динамические языки безопаснее, чем некоторые статические языки. (Python в целом считается намного безопаснее, чем Си). Когда хочется делать обобщения о статических или динамических языках как группах, то не забывайте об огромном количестве отличий между языками.

Явное и неявное назначение типов

Основная статья: Вывод типов

Многие статические системы типов, например, такие как в языках Си и Java, требуют провозглашения типа: программист должен явно назначать каждой переменной конкретный тип. Другие, такие как система типов Хиндли — Милнера, применяемая в языках ML и Haskell, осуществляют выведение типов: компилятор выстраивает заключение о типах переменных на основании того, как программист использует эти переменные.

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

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

Вообще говоря, выведение типов возможно, если оно принципиально разрешимо в теории типов. Более того, даже если выведение неразрешимо для данной теории типов, выведение зачастую возможно для многих реальных программ. Система типов языка Haskell, являющаяся разновидностью системы типов Хиндли — Милнера, представляет собой ограничение для так называемых полиморфных типов первого ранга, на которых выведение разрешимо. Многие компиляторы Хаскела предоставляют полиморфизм произвольного ранга в качестве расширения, но это делает выведение типов неразрешимым, так что требуется явное провозглашение типов. Однако, проверка согласования типов остаётся разрешимой и для программ с полиморфизмом первого ранга типы по-прежнему выводимы.

Конкретные примеры отличия в возможностях систем типизации

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

В Go можно сказать «функция add принимает два integer’а и возвращает integer»:

В Haskell можно сказать «функция принимает любой численный тип и возвращает число того же типа»:

В Idris можно сказать «функция принимает два integer’а и возвращает integer, но первый аргумент должен быть меньше второго аргумента»:

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

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

Специальные системы типов

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

Экзистенциальные типы

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

Понятие экзистенциального типа часто используется совместно с понятием типа записи для представления модулей и абстрактных типов данных, что обусловлено их назначением — отделением реализации от интерфейса. Например, тип описывает интерфейс модуля (семейства модулей с одинаковой сигнатурой), имеющий в своём составе значение данных типа и функцию, принимающую параметр в точности этого же типа и возвращающую целое число. Реализация может быть различной:

Оба типа являются подтипами более общего экзистенциального типа и соответствуют конкретно реализованным типам, так что любое значение, принадлежащее любому из них, принадлежит также к типу . Если  — значение типа , то проходит проверку типов, вне зависимости от того, к какому абстрактному типу принадлежит . Это даёт гибкость при выборе типов, подходящих для конкретной реализации, так как пользователи извне обращаются только к значениям интерфейсного (экзистенциального) типа и изолированы от этих вариаций.

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

intT = { a: int; f: (int → int); } as ∃X { a: X; f: (X → int); }

Хотя абстрактные типы данных и модули использовались в языках программирования довольно давно, формальная модель экзистенциальных типов была построена лишь к 1988 году. Теория представляет собой типизированное лямбда-исчисление второго порядка, аналогичное Системе F, но с экзистенциальной квантификацией вместо универсальной.

Экзистенциальные типы явным образом доступны в качестве экспериментального расширения языка Haskell, где они представляют собой специальный синтаксис, позволяющий использовать переменную типа в определении алгебраического типа, не вынося её в сигнатуру конструктора типов, то есть не повышая его арность. Язык Java предоставляет ограниченную форму экзистенциальных типов посредством . В языках, реализующих классический в стиле ML, экзистенциальные типы могут быть симулированы посредством так называемых «значений, индексированных типами».

Описание

Пример простой системы типов можно видеть в языке Си. Части программы на Си оформляются в виде определений функций. Функции вызывают друг друга. Интерфейс функции задаёт имя функции и список значений, которые передаются её телу. Вызывающая функция постулирует имя функции, которую хочет вызвать, и имена переменных, хранящих значения, которые требуется передать. Во время исполнения программы значения помещаются во временное хранилище, и затем исполнение передаётся в тело вызываемой функции. Код вызываемой функции осуществляет доступ к значениям и использует их. Если инструкции в теле функции написаны в предположении, что им на обработку должно быть передано целое значение, но вызывающий код передал число с плавающей точкой, то вызванная функция вычислит неверный результат. Компилятор Си проверяет типы, заданные для каждой переданной переменной, в отношении к типам, заданным для каждой переменной в интерфейсе вызываемой функции. Если типы не совпадают, компилятор порождает ошибку времени компиляции.

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

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

Компилятор также может использовать статический тип значения для оптимизации хранилища и для выбора алгоритмической реализации операций над этим значением. Например, во многих компиляторах Си тип представляется 32 битами, в соответствии со спецификацией IEEE для операций с плавающей точкой одинарной точности. На основании этого будет использоваться специальный набор инструкций микропроцессора для значений этого типа (сложение, умножение и другие операции).

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

Сильная и слабая типизация

Понятия «сильный» и «слабый» — очень неоднозначные. Вот некоторые примеры их использования:

  • Иногда «сильный» означает «статический».
    Тут все просто, но лучше использовать термин «статический», потому что большинство используют и понимают его.

  • Иногда «сильный» означает «не делает неявное преобразование типов».
    Например, JavaScript позволяет написать , что можно назвать «слабой типизацией». Но почти все языки предоставляют тот или иной уровень неявного преобразования, которое позволяет автоматически переходить от целых чисел к числам с плавающей запятой вроде . В реальности, большинство людей используют слово «сильный» для определения границы между приемлемым и неприемлемым преобразованием. Нет какой-то общепринятой границы, они все неточные и зависят от мнения конкретного человека.

  • Иногда «сильный» означает, что невозможно обойти строгие правила типизации в языке.

  • Иногда «сильный» означает безопасный для памяти (memory-safe).
    Си — это пример небезопасного для памяти языка. Если — это массив четырех чисел, то Си с радостью выполнит код или , возвращая какое-то значение из памяти, которая находится сразу за .

Давайте остановимся. Вот как некоторые языки отвечают этим определениям. Как можно заметить, только Haskell последовательно «сильный» по всем параметрам. Большинство языков не такие четкие.

Язык Статический? Неявные преобразования? Строгие правила? Безопасный для памяти?
C Сильный Когда как Слабый Слабый
Java Сильный Когда как Сильный Сильный
Haskell Сильный Сильный Сильный Сильный
Python Слабый Когда как Слабый Сильный
JavaScript Слабый Слабый Слабый Сильный

(«Когда как» в колонке «Неявные преобразования» означает, что разделение между сильным и слабым зависит от того, какие преобразования мы считаем приемлемыми).

Зачастую термины «сильный» и «слабый» относятся к неопределенной комбинации разных определений выше, и других, не показанных здесь определений. Весь этот беспорядок делает слова «сильный» и «слабый» практически бессмысленными. Когда хочется использовать эти термины, то лучше описать, что конкретно имеется ввиду. Например, можно сказать, что «JavaScript возвращает значение, когда складывается строка с числом, но Python возвращает ошибку». В таком случае мы не будем тратить свои силы на попытки прийти к соглашению о множестве значений слова «сильный». Или, еще хуже: придем к неразрешенному непониманию из-за терминологии.

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

Как написал Крис Смит:

Грушевая сгущенка

Категория:
Заготовки Варенье

Вкус у этой закрутки напоминает не то фруктовые ириски, не то сгущенку с грушевым привкусом. Отсюда и название. Рецепт мне достался не проверенным, и по этой причине, честно говоря, готовила я эту сладость с некоторой опаской. Так как раньше подобного не делала, то приготовила себя морально к любому исходу. Но вы знаете, получилось очень даже прилично, а для сладкоежек — вообще находка! Думаю, что холодными зимними вечерами с чайком все уйдет на ура!

Виды типизации

Обычно типизацию описывают несколькими словами, например, говорят, что

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

Сильная / слабая типизация (тоже самое, что строгая / нестрогая)

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

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

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

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

Например, Pascal относится к языкам с сильной типизацией (например поэтому в Паскале нельзя конкатенировать строки и числа), но тем не менее возможно, например преобразование целого числа к вещественному в неявном виде, подобное явление называют «ограниченное неявное преобразование» (подробнее см. источник 1).

Примеры

  • Сильная типизация: Java, Python, Haskell, Pascal, Lisp;
  • Слабая типизация: C, JavaScript, Visual Basic, PHP.

Статическая / динамическая типизация

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

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

Примеры:

  • Статическая: Pascal, C, Java, C#;
  • Динамическая: Python, JavaScript, Ruby, PHP

Явная / неявная типизация

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

Примеры:

  • Явная: C++, D, C#
  • Неявная: PHP, Lua, JavaScript

Инерционные характеристики