Прежде всего я хочу сказать, что Java - единственный язык, который я когда-либо использовал, поэтому прошу прощения за мое незнание этого вопроса.
Динамически типизированные языки позволяют вам помещать любое значение в любую переменную. Так, например, вы можете написать следующую функцию (psuedocode):
void makeItBark(dog){
dog.bark();
}
И вы можете передать в нем любое значение. Пока значение имеет bark()
метод, код будет выполняться. В противном случае выдается исключение во время выполнения или что-то подобное. (Пожалуйста, поправьте меня, если я ошибаюсь по этому поводу).
По-видимому, это дает вам гибкость.
Однако я немного читал о динамических языках, и люди говорят, что при разработке или написании кода на динамическом языке вы думаете о типах и учитываете их так же, как и в языке со статической типизацией.
Например, когда вы пишете makeItBark()
функцию, вы намереваетесь принять только «вещи, которые могут лаять», и вам все равно нужно убедиться, что вы пропускаете в нее только такие вещи. Разница лишь в том, что теперь компилятор не сообщит вам, когда вы допустили ошибку.
Конечно, у этого подхода есть одно преимущество, заключающееся в том, что в статических языках для достижения «эта функция принимает все, что может лаять», вам необходимо реализовать явный Barker
интерфейс. Тем не менее, это кажется незначительным преимуществом.
Я что-то пропустил? Что я на самом деле получаю, используя динамически типизированный язык?
источник
makeItBark(collections.namedtuple("Dog", "bark")(lambda x: "woof woof"))
, Этот аргумент даже не класс , это аноним с именем кортеж. Утиная печать («если она крякает как ...») позволяет создавать специальные интерфейсы с практически нулевыми ограничениями и без синтаксических накладных расходов. Вы можете сделать это на таком языке, как Java, но в итоге вы получите много грязных размышлений. Если функция в Java требует ArrayList и вы хотите присвоить ей другой тип коллекции, вы SOL. В питоне это даже не может всплыть.bark()
метод, при этом компилятор жалуется, когда вы передаете что-то неправильно, но без необходимости фактически объявлять интерфейс, содержащий bark ().getMember
функции, онаmakeItBark
взрывается из-за того, что вы вызвали ееdog.bark
вместоdog.getMember("bark")
. То, что заставляет код работать, - то, что все неявно соглашаются использовать нативный тип объекта Python.Just because I wrote makeItBark with my own types in mind doesn't mean you can't use yours, wheras in a static language it probably /does/ mean that.
Как указано в моем ответе, это не так в целом . Это относится к Java и C #, но эти языки имеют ограниченные системы типов и модулей, поэтому они не представляют, что может делать статическая типизация. Я могу написать совершенно универсальный языкmakeItBark
для нескольких статически типизированных языков, даже нефункциональных, таких как C ++ или D.Ответы:
Динамически типизированные языки не типизированы
Сравнивая системы типов , в динамической типизации нет преимуществ. Динамическая типизация - это особый случай статической типизации - это язык статической типизации, где каждая переменная имеет один и тот же тип. Вы можете добиться того же в Java (за исключением краткости), сделав каждую переменную типовой
Object
, а значения «объект» - типомMap<String, Object>
:Таким образом, даже без размышлений вы можете добиться того же эффекта практически на любом языке со статической типизацией, за исключением синтаксического удобства. Вы не получаете никакой дополнительной выразительной силы; напротив, вы обладаете меньшей выразительной силой, потому что в динамически типизированном языке вы лишены возможности ограничивать переменные определенными типами.
Изготовление утиной коры на языке статической типизации
Кроме того, хороший статически типизированный язык позволит вам писать код, который работает с любым типом, у которого есть
bark
операция. В Haskell это класс типов:Это выражает ограничение, что для того, чтобы некоторый тип
a
считался Barkable, должна существоватьbark
функция, которая принимает значение этого типа и ничего не возвращает.Затем вы можете написать универсальные функции в терминах
Barkable
ограничения:Это говорит о том, что
makeItBark
будет работать для любого типа, удовлетворяющегоBarkable
требованиям. Это может показаться похожим наinterface
Java или C #, но у него есть одно большое преимущество - типы не должны заранее указывать , какие классы типов они удовлетворяют. Я могу сказать , что типDuck
являетсяBarkable
в любое время, даже еслиDuck
это тип третьей стороны , я не писал. На самом деле, не имеет значения, что авторDuck
не написалbark
функцию - я могу предоставить ее после факта, когда я говорю на языке, которыйDuck
удовлетворяетBarkable
:Это говорит о том, что
Duck
s может лаять, и их функция лая реализуется путем удара по утке перед тем, как ее крякнуть. С этим из пути мы можем призватьmakeItBark
уток.Standard ML
иOCaml
еще более гибки в том, что вы можете удовлетворить один и тот же класс типов несколькими способами. В этих языках я могу сказать, что целые числа можно упорядочить, используя обычное упорядочение, а затем развернуться и сказать, что они также можно упорядочить по делимости (например,10 > 5
потому что 10 делится на 5). В Haskell вы можете создать экземпляр класса типов только один раз. (Это позволяет Haskell автоматически знать, что можно вызыватьbark
утку; в SML или OCaml вы должны четко указывать, какуюbark
функцию вы хотите, потому что их может быть несколько).сжатость
Конечно, есть синтаксические различия. Код Python, который вы представили, гораздо более лаконичен, чем Java-эквивалент, который я написал. На практике эта краткость является большой частью привлекательности динамически типизированных языков. Но вывод типов позволяет вам писать код, который так же лаконичен для языков со статической типизацией, избавляя вас от необходимости явно писать типы каждой переменной. Язык со статической типизацией может также обеспечить встроенную поддержку динамической типизации, удаляя многословие всех операций приведения и преобразования карт (например, C #
dynamic
).Правильные, но плохо набранные программы
Чтобы быть справедливым, статическая типизация обязательно исключает некоторые программы, которые являются технически правильными, даже если средство проверки типов не может это проверить. Например:
В большинстве языков со статической типизацией это
if
утверждение будет отклонено , хотя ветвь else никогда не появится. На практике кажется, что никто не использует этот тип кода - что-либо слишком умное для проверки типов, вероятно, заставит будущих сопровождающих вашего кода проклинать вас и ваших ближайших родственников. Например, кто-то успешно перевел 4 проекта с открытым исходным кодом на Python на Haskell, что означает, что они не делали ничего, что не смог бы скомпилировать хороший статически типизированный язык. Более того, компилятор обнаружил пару ошибок, связанных с типами, которые модульные тесты не улавливали.Самый сильный аргумент, который я видел для динамической типизации, - это макросы Lisp, поскольку они позволяют произвольно расширять синтаксис языка. Однако Typed Racket - это статически типизированный диалект Lisp, в котором есть макросы, поэтому статическая типизация и макросы не являются взаимоисключающими, хотя, возможно, сложнее реализовать одновременно.
Яблоки и апельсины
Наконец, не забывайте, что различия в языках намного больше, чем просто в системе типов. До Java 8 любое функциональное программирование на Java было практически невозможно; простая лямбда потребует 4 строки стандартного кода анонимного класса. Java также не поддерживает литералы коллекций (например
[1, 2, 3]
). Также могут быть различия в качестве и доступности инструментов (IDE, отладчиков), библиотек и поддержки сообщества. Когда кто-то заявляет, что он более продуктивен в Python или Ruby, чем в Java, необходимо учитывать это несоответствие функций. Существует разница между сравнением языков со всеми включенными батареями , языковыми ядрами и системами типов .источник
Это сложный и довольно субъективный вопрос. (И ваш вопрос может быть закрыт как основанный на мнении, но это не значит, что это плохой вопрос - наоборот, даже думать о таких вопросах на мета-языке - хороший знак - он просто не очень подходит для формата вопросов и ответов этого форума.)
Вот мое мнение об этом: Смысл языков высокого уровня состоит в том, чтобы ограничить то, что программист может делать с компьютером. Это удивляет многих людей, так как они считают, что цель состоит в том, чтобы дать пользователям больше возможностей и достичь большего . Но поскольку все, что вы пишете в Prolog, C ++ или List, в конечном итоге выполняется как машинный код, на самом деле невозможно дать программисту больше возможностей, чем уже обеспечивает язык ассемблера.
Смысл языка высокого уровня состоит в том, чтобы помочь программисту лучше понять код, который они сами создали, и сделать его более эффективным при выполнении того же самого. Имя подпрограммы легче запомнить, чем шестнадцатеричный адрес. Автоматический счетчик аргументов проще в использовании, чем последовательность вызовов, здесь вы должны точно определить количество аргументов самостоятельно, без посторонней помощи. Система типов идет дальше и ограничивает тип аргументов, которые вы можете предоставить в данном месте.
Вот где восприятие людей отличается. Некоторые люди (я в их числе) считают, что если ваша подпрограмма проверки пароля все равно будет ожидать ровно два аргумента и всегда строку, за которой следует числовой идентификатор, полезно объявить это в коде и автоматически напоминать, если позже вы забудете следовать этому правилу. Аутсорсинг такого мелкомасштабного бухгалтерского учета компилятору помогает освободить ваш ум от проблем более высокого уровня и делает вас лучше при проектировании и архитектуре вашей системы. Следовательно, системы типов - это чистая победа: они позволяют компьютеру делать то, в чем он хорош, а люди делают то, в чем они хороши.
Другие видят совсем по-другому. Им не нравится, когда компилятор говорит, что делать. Им не нравятся дополнительные предварительные усилия, чтобы принять решение об объявлении типа и набрать его. Они предпочитают исследовательский стиль программирования, в котором вы пишете реальный бизнес-код без плана, который бы точно указывал, какие типы и аргументы использовать где. И для стиля программирования, который они используют, это может быть совершенно верно.
Конечно, я слишком сильно упрощаю. Проверка типов не связана строго с явными объявлениями типов; есть также вывод типа. Программирование с помощью процедур, которые на самом деле принимают аргументы разных типов, допускает совершенно разные и очень мощные вещи, которые в противном случае были бы невозможны, просто многие люди недостаточно внимательны и последовательны, чтобы успешно использовать такую свободу действий.
В конце концов, тот факт, что такие разные языки очень популярны и не показывают никаких признаков отмирания, показывает, что люди занимаются программированием совершенно по-разному. Я думаю, что особенности языка программирования в значительной степени связаны с человеческими факторами - что лучше поддерживает процесс принятия решений человеком - и пока люди работают совсем по-другому, рынок будет предлагать очень разные решения одновременно.
источник
Код, написанный с использованием динамических языков, не связан со статической системой типов. Следовательно, это отсутствие сцепления является преимуществом по сравнению с плохими / неадекватными системами статического типа (хотя это может быть стирка или недостаток по сравнению с отличной системой статического типа).
Кроме того, для динамического языка не требуется разрабатывать, реализовывать, тестировать и поддерживать систему статических типов. Это может сделать реализацию проще по сравнению с языком со статической системой типов.
источник