Я знаю, что динамически типизированные языки никогда не позволяют разработчикам указывать типы переменных или, по крайней мере, имеют очень ограниченную поддержку для этого.
Например, JavaScript не предоставляет никакого механизма для принудительного применения типов переменных, когда это удобно делать. PHP позволяют определить некоторые типы аргументов методы, но нет никакого способа , чтобы использовать собственные типы ( int
, string
и т.д.) для аргументов, и нет никакого способа , чтобы обеспечить соблюдение типов для ничего, кроме аргументов.
В то же время было бы удобно иметь возможность указать в некоторых случаях тип переменной в динамически типизированном языке вместо проверки типа вручную.
Почему существует такое ограничение? Это связано с техническими / производительными причинами (я полагаю, что это в случае JavaScript), или только по политическим причинам (что, я полагаю, в случае с PHP)? Это относится к другим динамически типизированным языкам, с которыми я не знаком?
Отредактируйте: следуя ответам и комментариям, вот пример для пояснения: допустим, у нас есть следующий метод в простом PHP:
public function CreateProduct($name, $description, $price, $quantity)
{
// Check the arguments.
if (!is_string($name)) throw new Exception('The name argument is expected to be a string.');
if (!is_string($description)) throw new Exception('The description argument is expected to be a string.');
if (!is_float($price) || is_double($price)) throw new Exception('The price argument is expected to be a float or a double.');
if (!is_int($quantity)) throw new Exception('The quantity argument is expected to be an integer.');
if (!$name) throw new Exception('The name argument cannot be an empty string.');
if ($price <= 0) throw new Exception('The price argument cannot be less or equal to zero.');
if ($price < 0) throw new Exception('The price argument cannot be less than zero.');
// We can finally begin to write the actual code.
// TODO: Implement the method here.
}
С некоторыми усилиями это можно переписать так (см. Также Программирование с помощью контрактов в PHP ):
public function CreateProduct($name, $description, $price, $quantity)
{
Component::CheckArguments(__FILE__, __LINE__, array(
'name' => array('value' => $name, 'type' => VTYPE_STRING),
'description' => array('value' => $description, 'type' => VTYPE_STRING),
'price' => array('value' => $price, 'type' => VTYPE_FLOAT_OR_DOUBLE),
'quantity' => array('value' => $quantity, 'type' => VTYPE_INT)
));
if (!$name) throw new Exception('The name argument cannot be an empty string.');
if ($price <= 0) throw new Exception('The price argument cannot be less or equal to zero.');
if ($price < 0) throw new Exception('The price argument cannot be less than zero.');
// We can finally begin to write the actual code.
// TODO: Implement the method here.
}
Но тот же метод был бы написан следующим образом, если бы PHP мог принимать нативные типы для аргументов:
public function CreateProduct(string $name, string $description, double $price, int $quantity)
{
// Check the arguments.
if (!$name) throw new Exception('The name argument cannot be an empty string.');
if ($price <= 0) throw new Exception('The price argument cannot be less or equal to zero.');
if ($price < 0) throw new Exception('The price argument cannot be less than zero.');
// We can finally begin to write the actual code.
// TODO: Implement the method here.
}
Какой из них короче написать? Какой из них легче читать?
источник
Ответы:
Смысл статической типизации - это возможность статически доказать, что ваша программа верна в отношении типов (примечание: не совсем корректно во всех смыслах). Если у вас есть статическая система типов, вы можете обнаруживать ошибки типов в большинстве случаев.
Если у вас есть только частичная информация о типе, вы можете проверить только небольшие фрагменты графа вызовов, где информация о типе оказывается полной. Но вы потратили время и силы на то, чтобы указать информацию о типе для неполных частей, где она не может помочь вам, но может дать ложное чувство безопасности.
Чтобы выразить информацию о типе, вам нужна часть языка, которая не может быть чрезмерно простой. Вскоре вы обнаружите, что такой информации
int
недостаточно; вам понадобится что-то вродеList<Pair<Int, String>>
, затем параметрические типы и т. д. Это может сбить с толку даже в довольно простом случае с Java.Затем вам нужно обрабатывать эту информацию во время фазы трансляции и фазы выполнения, потому что это глупо , чтобы проверить только для статических ошибок; пользователь будет ожидать, что ограничения типа всегда выполняются, если указаны вообще. Динамические языки не слишком быстрые, и такие проверки еще больше замедляют производительность. Статический язык может тратить серьезные усилия на проверку типов, потому что он делает это только один раз; динамический язык не может.
Теперь представьте, что вы добавляете и поддерживаете все это просто для того, чтобы люди иногда могли использовать эти функции, обнаруживая лишь небольшую часть ошибок типа. Я не думаю, что это стоит усилий.
Суть динамических языков в том, чтобы иметь очень маленькую и очень податливую среду, в которой вы можете легко делать вещи, которые гораздо более сложны при работе на статическом языке: различные формы мартышечных патчей, которые используются для метапрограммирования, насмешек и тестирование, динамическая замена кода и т. д. Smalltalk и Lisp, оба очень динамичные, довели его до такой степени, что отправляют образы среды вместо сборки из исходного кода. Но когда вы хотите убедиться, что конкретные пути данных безопасны для типов, добавьте утверждения и напишите больше модульных тестов.
источник
В большинстве динамических языков вы можете по крайней мере динамически тестировать тип объекта или значения.
Кроме того, для некоторых динамических языков существуют статические средства определения типов, средства проверки и / или применения:
А Perl 6 будет поддерживать опциональную систему типов со статической типизацией.
Но я предполагаю, что суть в том, что многие люди используют динамические языки, потому что они динамически типизированы, и для них необязательная статическая типизация очень «хо-хо». И многие другие люди используют их, потому что они «просты в использовании для непрограммистов», в значительной степени вследствие прощающего характера динамической типизации. Для них необязательная типизация - это то, что они либо не поймут, либо не будут использовать.
Если бы вы были циничны, вы могли бы сказать, что дополнительная статическая типизация предлагает худшее из обоих миров. Для фанатиков статического типа это не предотвращает всех сбоев динамического типа. Для фанатов динамического типа это все еще прямая куртка ... хотя и с не пристегнутыми ремнями.
источник
Javascript планировал включить некоторую необязательную статическую типизацию, и кажется, что многие зрелые динамические языки движутся в этом направлении.
Причина в том, что когда вы впервые пишете код, вы хотите быть быстрым и динамически набираемым. Как только ваш код будет надежным, работающим и будет много использовать, вы захотите заблокировать дизайн, чтобы уменьшить количество ошибок. (это выгодно как пользователям, так и разработчикам, так как первый получит проверку на ошибки на своих вызовах, а второй не сломает случайно.
Это имеет какой-то смысл для меня, так как я обычно нахожу там слишком много проверки типов в начале проекта, слишком мало в конце его жизненного цикла, независимо от того, какой язык я использую;).
источник
Объекты Python сделать имеют тип.
Вы указываете тип при создании объекта.
На самом деле, ручная проверка типов в Python - это почти всегда пустая трата времени и кода.
Это просто плохая практика - писать код проверки типа в Python.
Если какой-то злонамеренный социопат использовал неподходящий тип, обычные методы Python вызовут обычное исключение, если тип не подходит.
Вы не пишете код, ваша программа по-прежнему не работает с
TypeError
.Есть очень редкие случаи, когда вы должны определить тип во время выполнения.
Поскольку это не «ограничение», вопрос не является реальным вопросом.
источник
Большую часть времени вам не нужно, по крайней мере, не на уровне детализации, который вы предлагаете. В PHP операторы, которые вы используете, делают совершенно ясным, какие аргументы вы ожидаете; Это немного упущение при проектировании, хотя PHP будет приводить ваши значения, если это вообще возможно, даже когда вы передаете массив операции, которая ожидает строку, и поскольку приведение не всегда имеет смысл, вы иногда получаете странные результаты ( и именно здесь полезны проверки типов ). Кроме этого, не имеет значения, если вы добавите целые числа
1
и /5
или строки"1"
и"5"
- сам факт того, что вы используете+
оператор сообщает PHP, что вы хотите рассматривать аргументы как числа, и PHP будет подчиняться. Интересная ситуация возникает, когда вы получаете результаты запроса из MySQL: многие числовые значения просто возвращаются в виде строк, но вы не заметите, так как PHP приводит их к вам всякий раз, когда вы рассматриваете их как числа.Python немного строже в своих типах, но в отличие от PHP, Python с самого начала имел исключения и использует их последовательно. Парадигма «проще просить прощения, чем разрешения» предлагает просто выполнить операцию без проверки типа и полагаться на исключение, возникающее, когда типы не имеют смысла. Единственный недостаток, о котором я могу подумать, это то, что иногда вы обнаружите, что где-то тип не соответствует ожидаемому, но найти причину может быть утомительно.
И есть еще одна причина: динамические языки не имеют стадии компиляции. Даже если у вас есть ограничения типа, они могут срабатывать только во время выполнения, просто потому, что нет времени компиляции . Если ваши проверки в любом случае приводят к ошибкам во время выполнения, гораздо проще соответствующим образом смоделировать их: как явные проверки (например,
is_XXX()
в PHP илиtypeof
в javascript) или путем генерирования исключений (как это делает Python). Функционально у вас есть тот же эффект (ошибка сигнализирует во время выполнения, когда проверка типа не проходит), но она лучше интегрируется с остальной семантикой языка. Просто не имеет смысла трактовать ошибки типа, принципиально отличающиеся от других ошибок времени выполнения в динамическом языке.источник
Вас может заинтересовать Haskell - это система типов, которая выводит типы из кода, и вы также можете указывать типы.
источник
Как упоминалось в других ответах, существует два подхода к типизации при реализации языка программирования.
Оба подхода являются действительными, и то, что использовать, зависит частично от технических соображений, таких как производительность, и частично от политических причин, таких как целевой рынок для языка.
источник
Прежде всего динамические языки созданы в основном для простоты использования. Как вы упомянули, действительно полезно автоматически выполнять преобразование типов и предоставлять нам меньше затрат. Но в то же время ему не хватает проблем с производительностью.
Вы можете придерживаться динамических языков, если вы не беспокоитесь о производительности. Скажем, например, JavaScript работает медленнее, когда нужно выполнить многократное преобразование типов в вашей программе, но это помогает уменьшить количество строк в вашем коде.
Следует отметить, что существуют и другие динамические языки, которые позволяют программисту указывать тип. Например, Groovy - один из известных динамических языков, который работает на JVM. И это было очень известным в последние дни даже. Обратите внимание, что производительность Groovy такая же, как у Java.
Надеюсь, это поможет вам.
источник
Это просто бессмысленно.
Почему?
Потому что система типов DTL точно такова, что типы не могут быть определены во время компиляции. Следовательно, компилятор не может даже проверить, что указанный тип имеет смысл.
источник
Посмотрите на Go, на поверхности он статически типизирован, но эти типы могут быть интерфейсами, которые по сути являются динамическими.
источник