Кажется, что все новые языки программирования или, по крайней мере, те, которые стали популярными, используют вывод типов. Даже Javascript получил типы и вывод типов через различные реализации (Acscript, typcript и т. Д.). Это выглядит великолепно для меня, но мне интересно, есть ли какие-то компромиссы или почему, скажем, Java или старые добрые языки не имеют вывода типа
- При объявлении переменной в Go без указания ее типа (с использованием var без типа или синтаксиса: =) тип переменной выводится из значения в правой части.
- D позволяет писать большие фрагменты кода без избыточного указания типов, как это делают динамические языки. С другой стороны, статический вывод выводит типы и другие свойства кода, предоставляя лучшее из статического и динамического миров.
- Механизм вывода типов в Rust довольно умный. Он делает больше, чем просто смотрит на тип значения r во время инициализации. Также выглядит, как переменная впоследствии используется для определения ее типа.
- Swift использует вывод типа для разработки подходящего типа. Вывод типа позволяет компилятору автоматически определять тип определенного выражения при компиляции вашего кода, просто проверяя предоставленные вами значения.
programming-languages
type-systems
Пользователь без шляпы
источник
источник
var
потому что это иногда может ухудшить читабельностьvar
и C ++auto
) и выводом типа (двунаправленный, как Haskelllet
). В первом случае тип имени может быть выведен только из его инициализатора - его использование должно соответствовать типу имени. В последнем случае тип имени также может быть выведен из его использования - что полезно в том смысле, что вы можете написать просто[]
для пустой последовательности, независимо от типа элемента, илиnewEmptyMVar
для новой пустой переменной, независимо от референта. тип.Ответы:
Система типов в Haskell полностью незаметна (оставляя в стороне полиморфную рекурсию, некоторые расширения языка и устрашающее ограничение мономорфизма ), однако программисты по-прежнему часто предоставляют аннотации типов в исходном коде, даже когда они не нужны. Зачем?
map :: (a -> b) -> [a] -> [b]
. Его более общая форма (fmap :: Functor f => (a -> b) -> f a -> f b
) применяется ко всемFunctor
s, а не только к спискам. Но считалось, чтоmap
это будет легче понять новичкам, поэтому он живет вместе со своим старшим братом.В целом, недостатки статически типизированной, но выводимой системы во многом совпадают с недостатками статической типизации в целом, изношенное обсуждение этого сайта и других («Недостатки статической типизации в поиске» принесут вам сотни страниц пламенных войн). Конечно, некоторые из указанных недостатков улучшаются благодаря меньшему количеству типовых аннотаций в выводимой системе. Кроме того, вывод типов имеет свои преимущества: разработка с использованием дырок невозможна без вывода типов.
Java * доказывает, что язык, требующий слишком большого количества аннотаций типов, становится раздражающим, но слишком мало вы теряете преимущества, описанные выше. Языки с логическим выводом типа «отказ от участия» обеспечивают приемлемый баланс между двумя крайностями.
* Даже Java, этот великий козел отпущения, выполняет определенное количество локальных выводов типов. В таком выражении, как
Map<String, Integer> = new HashMap<>();
, вам не нужно указывать универсальный тип конструктора. С другой стороны, языки в стиле ML, как правило, являются глобально выводимыми.источник
Functor
. Списки иmap
, скорее всего, знакомы для неопытных Хаскеллеров.var
примером вывода типа?var
- правильный пример.x
; в последнем нет типа для определения, все типы известны, и вам просто нужно проверить, что выражение имеет смысл. Разница становится более важной, когда вы переходите от простых примеров иx
используется в нескольких местах; Затем компилятор должен перепроверить места, гдеx
он используется для определения 1) можно ли назначитьx
тип так, чтобы код проверял тип? 2) Если это так, какой самый общий тип мы можем назначить?new HashMap<>();
синтаксис был добавлен только в Java 7, а лямбда-выражения в Java 8 допускают довольно много «реальных» выводов типа.В C # вывод типов происходит во время компиляции, поэтому стоимость времени выполнения равна нулю.
По стилю
var
используется для ситуаций, когда вручную или неудобно указывать тип вручную. Linq - одна из таких ситуаций. Другой это:без которого вы будете повторять свое действительно длинное имя типа (и параметры типа), а не просто говорить
var
.Используйте фактическое имя типа, когда оно явное, улучшает ясность кода.
В некоторых ситуациях невозможно использовать определение типа, например, объявления переменных-членов, значения которых установлены во время построения, или когда вы действительно хотите, чтобы intellisense работал правильно (IDE Hackerrank не будет intellisense для членов переменной, если вы не объявите тип явно) ,
источник
Хороший вопрос!
И есть более эзотерические языки, которые не могут делать свои странности без явной аннотации типов. Пока что я не знаю ничего такого, что было бы достаточно распространенным / популярным / многообещающим, чтобы упомянуть, за исключением случая.
источник
var foo = x => x;
неудача, потому что язык должен выводитьx
здесь и дальше нечего. Когда лямбда-выражения создаются, они создаются как делегаты с явной типизацией,Func<int, int> foo = x => x
встроенные в CIL, какFunc<int, int> foo = new Func<int, int>(x=>x);
где лямбда- выражение создается как сгенерированная, явно типизированная функция. Для меня вывод типаx
является неотъемлемой частью вывода типа ...x => x
, содержится внутри самой лямбды - она не ссылается ни на какие переменные из окружающей области видимости. Любой нормальный функциональный язык будет правильно сделать вывод , что его типа «для всех типовa
,a -> a
». Я думаю, что DeadMG пытается сказать, что в системе типов C # отсутствует свойство основного типа, что означает, что всегда можно определить наиболее общий тип для любого выражения. Это очень легко разрушить.Ява оказывается скорее исключением, чем правилом. Даже C ++ (который, как я полагаю, квалифицируется как «старый добрый язык» :)) поддерживает вывод типа с
auto
ключевым словом начиная со стандарта C ++ 11. Он работает не только с объявлением переменной, но и с типом возвращаемого значения функции, что особенно удобно для некоторых сложных шаблонных функций.Неявная типизация и вывод типов имеют много хороших вариантов использования, а также есть некоторые случаи, когда вам действительно не следует этого делать. Иногда это дело вкуса, а также предмет спора.
Но то, что есть, несомненно, хорошие варианты использования, само по себе является законной причиной для любого языка для его реализации. Это также не сложно реализовать функцию, без штрафа за время выполнения, и не влияет существенно на время компиляции.
Я не вижу реального недостатка в том, чтобы дать возможность разработчику использовать вывод типа.
Некоторые респонденты рассуждали о том, что иногда явная типизация хороша, и они, безусловно, правы. Но не поддержка неявной типизации будет означать, что язык постоянно вводит явную типизацию.
Таким образом, реальный недостаток заключается в том, что язык не поддерживает неявную типизацию, поскольку при этом утверждается, что у разработчика нет законной причины использовать его, что не соответствует действительности.
источник
Основное различие между системой логического вывода типа Хиндли-Милнера и логическим типом логического вывода заключается в направлении потока информации. В HM информация типа передается вперед и назад через унификацию; в Go информация о типах передается только перенаправлениями: она рассчитывает только перестановки подстановок.
Вывод типа HM - это великолепная инновация, которая хорошо работает с функциональными языками с полиморфной типизацией, но авторы Go, вероятно, утверждают, что он пытается сделать слишком много:
Тот факт, что информация передается как вперед, так и назад, означает, что вывод типа HM является очень нелокальным делом; в отсутствие аннотаций типов каждая строка кода в вашей программе может способствовать вводу одной строки кода. Если у вас есть только прямое замещение, вы знаете, что источником ошибки типа должен быть код, предшествующий вашей ошибке; не код, который идет после.
С выводом типа HM вы склонны думать в ограничениях: когда вы используете тип, вы ограничиваете возможные типы. В конце дня, могут быть некоторые переменные типа, которые остаются полностью без ограничений. Понимание вывода типов HM состоит в том, что эти типы действительно не имеют значения, и поэтому они превращаются в полиморфные переменные. Однако этот дополнительный полиморфизм может быть нежелательным по ряду причин. Во-первых, как отмечают некоторые люди, этот дополнительный полиморфизм может быть нежелателен: HM завершает фиктивный, полиморфный тип для некоторого поддельного кода и позже приводит к странным ошибкам. Во-вторых, когда тип остается полиморфным, это может иметь последствия для поведения во время выполнения. Например, чрезмерно полиморфный промежуточный результат является причиной, по которой «шоу». читать 'считается в Хаскеле неоднозначным; в качестве другого примера,
источник
Это вредит читабельности.
сравнить
против
Это особенно проблема при чтении вне IDE, как на github.
источник
var
можете использовать его без ущерба для читабельности.var objects = GetBusinessObjects();