Страницы

Поиск по вопросам

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

пятница, 14 февраля 2020 г.

Типизация языка С++

#cpp #типизация


С++ — это статически типизированный язык. Я не могу понять, почему так, если, например,
понижающее приведение типов (dynamic cast, разумеется) в ветке наследования с полиморфным
родителем является проверкой типов во время выполнения программы.

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


Ответы

Ответ 1



Насколько я понимаю, в языках с динамической типизацией (например, Python, JavaScript, Lisp ..., не говоря уж о разных Shell-ах) один и тот же идентификатор (переменная) может иметь значения разных типов во время выполнения программы. В C++ же, тип данных, значения которого может принимать переменная, определяется статически (во время написания программы). Поэтому наличие механизма RTTI (в частности dynamic cast), проводящего некоторые проверки типов во время выполнения, не делает C++ языком с динамической типизацией.

Ответ 2



Наверное, потому что тип наследника ЯВЛЯЕТСЯ типом родителя, так что проверка допустимости типов все-таки выполняется во время компиляции, т.е. является статической.

вторник, 31 декабря 2019 г.

nil в языках программирования

#проектирование #любой_язык #null #типизация


Меня интересует как используется nil в различных языках программирования, и вообще
насколько это удобно с точки зрения дизайна языка.
В данной теме обсуждаются исключительно динамически типизированные языки.
К примеру в JavaScript есть два значения похожих на nil: null и undefined. (Нужно
ли было плодить?)
В Scheme есть #f, но нет nil. В Factor тоже нету nil, и используют f. (Нужен ли nil
если есть false?)
Кроме того, как-то читал что вроде в первых версиях Objective-C был объект nil (Objective-C
не знаю вообще), который поглощал вызовы, был чёрной дырой. Т.е. вёл себя как NaN для
чисел. На любое сообщение объект возвращал nil.
Насколько допустимо трактовать "пустые" объекты (пустой список, пустой словарь и
т.д.) как false, и есть ли у такой фичи опасные побочные эффекты, или вообще расположение
к каким-либо багам.
Приветствуются:

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


Ответы

Ответ 1



NULL нужен там, где есть ссылки. Почему в JavaScript есть еще undefined? Потому что null и undefined - разные объекты. По умолчанию ссылка указывает на undefined, а null - элемент логики. Сейчас ссылка null, потом не null. Скажем так, в С/С++ указатели тоже не null изначально, а undefined. Пустые объекты - не false, потому что false - семантическое значение. Элемент логических выражений, а null - нет (несмотря на то, что он используется в них, он преобразовывается). Если кратко, то наличие пустого объекта обязательно для языков со ссылками, а false - это отдельный объект, такой же как строка "ABC" или 4 - т.е. непустой, а семантически значимый.

Ответ 2



Хотя автор и задает вопрос по смыслу nil/null по отношению к динамическим языкам, но я считаю, что наиболее ярко смысл NULL раскрывается в SQL, а именно в случае со связанными запросами: пресловутые inner/left/right join). Без понятия NULL (то есть нет данных) весь SQL сильно теряет, если не сказать большего - вообще невозможно становится работать без NULL.

Ответ 3



Я считаю, что использование NULL важно в процессе отладки программы (скрипта). false - это все же нормальное значение переменной, а вот NULL - это именно отсутствие какого либо значения, вернее оно ПУСТОЕ. Обращение к NULL переменной может вызвать определенные исключительные ситуации, которые всегда вызовут ошибку работы программы, и именно это дает возможность легко найти и устранить эти ошибки. Я всегда использую именно NULL, как при возврате значений из функций, так и при передаче значений в функцию. Проверяю не просто !переменная, а именно == != NULL... На мой взгляд так красивее )) Удачи в поисках ответов!

понедельник, 23 декабря 2019 г.

Почему интерпретатор питона не проверяет type hints?

#python #python_3x #language_lawyer #дизайн_языка #типизация


Здравствуйте! В питоне есть type hint`ы, однако код вроде такого:

def add(a: int, b: int) -> int:
    return a + b

add('hello', 'world')


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

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

Что-то такое, кажется, не сложнее парсить:

#: int, int -> int
def add(a, b):
    return a + b

#: [int]
li = [1,2,3]


В том же js есть "strict mode", который можно включать и выключать по собственному
желанию, мне кажется, что это намного логичнее. Понятно, что задачи у них разные, но
ситуации, кажется, похожи.
    


Ответы

Ответ 1



Type hint'ы введены PEP 484. Держите под рукой. почему синтаксис в язык добавили, а проверки из коробки нет? Вообще на любые вопросы "почему в языке Х нет фичи Y", при отсутствии явного отказа от неё, ответ "не сделали ещё, может быть когда-нибудь". Но в PEP 484 есть предложение, очень похожее на отказ делать это частью языка: It should also be emphasized that Python will remain a dynamically typed language, and the authors have no desire to ever make type hints mandatory, even by convention. Важно также отметить, что Python останется динамически типизированным языком, и его авторы не намереваются когда-либо делать type hint'ы обязательными, даже если лишь по соглашению. Хотя это напрямую не исключает возможности появления необязательных проверок в стандартной библиотеке, это стало бы существенным шагом в сторону "статической типизации по соглашению", чего авторы языка не хотят. Как бы там ни было, type hint'ы должны стабилизироваться в языке, прежде чем основывать на них такую крупную фичу, как встроеннные проверки. А это случится не раньше Python 3.8. Ведь внешние утилиты могут проверять без какого либо дополнительного синтаксиса Да, но: Каждый анализатор вынужден для этого вводить собственный синтаксис. Возможно, когда-нибудь разные реализации пришли бы к общему де-факто стандарту. А можно сделать "превентивный стандарт", чтобы исключить другие развития событий на корню. Этот синтаксис должен затруднять написание аннотаций, несовместимых с описываемым кодом. Комментарии очень легко сделать несовместимыми с кодом, чтобы это не случилось, нужны дополнительные проверки самого кода. Разбирать сам код на Python разумно парсером Python, а не создавать и поддерживать его кусочек по новой. И если уж заставлять этим заниматься парсер Python, можно интегрировать синтаксис плотнее в язык, например указывать тип аргумента непосредственно рядом с ним. Что уже сделано аннотациями в PEP 3107, но аннотации постепенно становятся только type hint'ами и больше ничем.

среда, 4 декабря 2019 г.

Язык программирования без null

#null #дизайн_языка #типизация


Энтони Хоар, человек который ввёл в употребление NULL-указатель высказал следующую мысль:

I call it my billion-dollar mistake. It was the invention of the null reference in
1965. At that time, I was designing the first comprehensive type system for references
in an object oriented language (ALGOL W). My goal was to ensure that all use of references
should be absolutely safe, with checking performed automatically by the compiler. But
I couldn't resist the temptation to put in a null reference, simply because it was
so easy to implement. This has led to innumerable errors, vulnerabilities, and system
crashes, which have probably caused a billion dollars of pain and damage in the last
forty years.

Простите, что не по-русски, не нашёл качественного перевода.
Суть в том, что он считает введение NULL ошибкой, которая стоила многих сил, и что
вместо введения NULL необходимо было ввести дополнительные проверки во время компиляции.
Мне интересно, возможна ли жизнь без NULL, и как это особенно согласуется с динамическими
языками (быть может для языков со статической типизацей этого и можно было избежать,
а для динамических -- нет?). Вообще, как много есть языков, которые обходятся без NULL
или эквивалента?
Как минимум один мне известен: Haskell.
UPD:


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

    


Ответы

Ответ 1



Проблема заключается не в самом null, его использование абсолютно легально, т.к. является по сути не артефактом конкретного языка программирования, а вычислительным приемом, паттерном, - общим для всей теории программирования. Всегда существуют вычислительные процессы (функции), работу которых можно оценивать с двух позиций: 1) есть результат; 2) нет результата. C этой точки зрения значение null есть унифицированный способ кодирования ситуации "нет результата". Проблема заключается в способе интеграции этого паттерна в систему типов языка. Значение null в большинстве языков не имеет типа, точнее, null является значением некоторого специального типа, являющегося подтипом ВСЕХ типов нашего языка. Поэтому null может быть числом, строкой, кнопкой пользовательского интерфейса, и вообще принимать любую форму. По сути дела, null - это "хак", непонятно как вписавшийся в статическую типизацию артефакт динамической типизации. Именно здесь начинаются проблемы, о которых пишет Хоар, и с которыми я согласен на 200%. Такой способ интеграции значения null означает, что в ЛЮБОМ месте, где мы ожидаем некоторое значение, мы можем получить null. И для нас как программистов нет способа гарантированно узнать, получим ли мы его или нет, а для компилятора гарантированно проверить, что в коде мы учли ту ситуацию, когда вместо ожидаемого результата получен null. Ситуацию могли бы несколько поправить (но не спасти!) хорошая документация и дисциплинированность программистов. Если бы не тот факт, что именно этих "добродетелей" в реальности почти не встретишь. Чтобы исправить проблемы null, нужно выполнить два условия: программисты должны быть лишены возможности использовать null в тех местах, где ЯВНО не объявили такую возможность; компилятор должен проверять и гарантировать нам, что клиентский код учел все такие ситуации, где вместо результата может быть получен null. Это можно сделать одним способом: сделать null значением некоторого обычного типа. В Haskell этим типом является Maybe, в Scala - Option, в F# - option. Значения null для этих языков называются соответственно Nothing, None и снова None. Тогда все встает на свои места: Выполнение 1-го условия: // Ошибка компиляции: мы не указали ЯВНО, что можно использовать None def notLessThan5(x: Int): Int = if (x >= 5) x else None // OK def notLessThan5(x: Int): Option[Int] = if (x >= 5) Some(x) else None Выполнение 2-го условия: // Ошибка компиляции: мы не учли, что notLessThan5() может не вернуть результата (вернуть None) println(notLessThan5(10) + notLessThan5(3)) // OK println(notLessThan5(10).getOrElse(5) + notLessThan5(3).getOrElse(5)) // напечатает 15 Во всех случаях соблюдение правильных принципов работы со значениями null проверит за нас компилятор, не допустив, чтобы NullPointerException "всплыла" в самый неподходящий момент во время эксплуатации программы. Проблемы null решены. Следует особенно заметить: мы не отказываемся от использования null. Мы просто интегрируем этот null в систему типов иначе, чем это сделано сейчас, в Java и им подобных. None, Nothing и проч. - есть точные эквиваленты null, только интегрированные в систему типов. Динамические языки программирования не используют преимущества статической типизации, поэтому все, что описано выше, их не касается. Избежать тех проблем, о которых говорил Хоар, в динамических языках нельзя в принципе - любая функция может вернуть ЛЮБОЕ значение. Это касается не только null, но вообще любых значений. Поэтому умные люди, которые используют динамические языки в повседневной практике, давно уже описали в литературе защитные практики от гибкости динамических языков. Основной практикой, помимо дисциплины и документации, является повсеместное и всеобъемлющее тестирование кода, причем как можно раньше, в идеале, до написания самого кода (TDD). Чудес не бывает: верификацию при проверке типов приходится заменять верификацией при тестировании. На эту тему рекомендую послушать великолепный доклад Robert Martin'а, произнесенный на RailsConf'09, "What Killed Smalltalk Could Kill Ruby, Too".

Ответ 2



Если поставить себе такую цель - написать программу не использующую NULL, скажем на C++, то это вполне осуществимо. Так что, в общем случае без NULL на C++ жить можно. На C# сложнее будет это сделать, поскольку большинство методов в .NET могут вернуть null. И как минимум проверять на null придется. Но это, согласитесь, уже не проблема языка, а проблема библиотек. Были бы библиотеки не использующие null, и программы можно было бы писать без него. К тому же, можно создать классы-обертки для того чтобы они инкапсулировали в себе работу с NULL и для внешнего наблюдателя никаких нулов не будет. Правильные программы на C++ пишутся именно так. Не думаю, что эти рассуждения не верны для других языков.

Ответ 3



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

четверг, 20 декабря 2018 г.

nil в языках программирования

Меня интересует как используется nil в различных языках программирования, и вообще насколько это удобно с точки зрения дизайна языка. В данной теме обсуждаются исключительно динамически типизированные языки. К примеру в JavaScript есть два значения похожих на nil: null и undefined. (Нужно ли было плодить?) В Scheme есть #f, но нет nil. В Factor тоже нету nil, и используют f. (Нужен ли nil если есть false?) Кроме того, как-то читал что вроде в первых версиях Objective-C был объект nil (Objective-C не знаю вообще), который поглощал вызовы, был чёрной дырой. Т.е. вёл себя как NaN для чисел. На любое сообщение объект возвращал nil Насколько допустимо трактовать "пустые" объекты (пустой список, пустой словарь и т.д.) как false, и есть ли у такой фичи опасные побочные эффекты, или вообще расположение к каким-либо багам. Приветствуются: Ссылки на статьи с обзором различных подходов Ссылки на какие-либо интересные языки, относящиеся к теме Обсуждение различных подходов, удобства и опасности использования


Ответ

NULL нужен там, где есть ссылки. Почему в JavaScript есть еще undefined? Потому что null и undefined - разные объекты. По умолчанию ссылка указывает на undefined, а null - элемент логики. Сейчас ссылка null, потом не null. Скажем так, в С/С++ указатели тоже не null изначально, а undefined. Пустые объекты - не false, потому что false - семантическое значение. Элемент логических выражений, а null - нет (несмотря на то, что он используется в них, он преобразовывается). Если кратко, то наличие пустого объекта обязательно для языков со ссылками, а false - это отдельный объект, такой же как строка "ABC" или 4 - т.е. непустой, а семантически значимый.

четверг, 11 октября 2018 г.

Язык программирования без null

Энтони Хоар, человек который ввёл в употребление NULL-указатель высказал следующую мысль: I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years. Простите, что не по-русски, не нашёл качественного перевода. Суть в том, что он считает введение NULL ошибкой, которая стоила многих сил, и что вместо введения NULL необходимо было ввести дополнительные проверки во время компиляции. Мне интересно, возможна ли жизнь без NULL, и как это особенно согласуется с динамическими языками (быть может для языков со статической типизацей этого и можно было избежать, а для динамических -- нет?). Вообще, как много есть языков, которые обходятся без NULL или эквивалента? Как минимум один мне известен: Haskell. UPD Для языков со статической типизацией можно проанализировать код и увидеть все ли переменные инициализированны. (Попробовать обойтись без NULL) Для динамических языков (не только с динамической типизацией, а таких, где есть eval или похожий инструмент) такого гарантированно сделать нельзя.


Ответ

Проблема заключается не в самом null, его использование абсолютно легально, т.к. является по сути не артефактом конкретного языка программирования, а вычислительным приемом, паттерном, - общим для всей теории программирования. Всегда существуют вычислительные процессы (функции), работу которых можно оценивать с двух позиций: 1) есть результат; 2) нет результата. C этой точки зрения значение null есть унифицированный способ кодирования ситуации "нет результата". Проблема заключается в способе интеграции этого паттерна в систему типов языка. Значение null в большинстве языков не имеет типа, точнее, null является значением некоторого специального типа, являющегося подтипом ВСЕХ типов нашего языка. Поэтому null может быть числом, строкой, кнопкой пользовательского интерфейса, и вообще принимать любую форму. По сути дела, null - это "хак", непонятно как вписавшийся в статическую типизацию артефакт динамической типизации. Именно здесь начинаются проблемы, о которых пишет Хоар, и с которыми я согласен на 200%. Такой способ интеграции значения null означает, что в ЛЮБОМ месте, где мы ожидаем некоторое значение, мы можем получить null. И для нас как программистов нет способа гарантированно узнать, получим ли мы его или нет, а для компилятора гарантированно проверить, что в коде мы учли ту ситуацию, когда вместо ожидаемого результата получен null. Ситуацию могли бы несколько поправить (но не спасти!) хорошая документация и дисциплинированность программистов. Если бы не тот факт, что именно этих "добродетелей" в реальности почти не встретишь. Чтобы исправить проблемы null, нужно выполнить два условия: программисты должны быть лишены возможности использовать null в тех местах, где ЯВНО не объявили такую возможность; компилятор должен проверять и гарантировать нам, что клиентский код учел все такие ситуации, где вместо результата может быть получен null. Это можно сделать одним способом: сделать null значением некоторого обычного типа. В Haskell этим типом является Maybe, в Scala - Option, в F# - option. Значения null для этих языков называются соответственно Nothing, None и снова None. Тогда все встает на свои места: Выполнение 1-го условия: // Ошибка компиляции: мы не указали ЯВНО, что можно использовать None def notLessThan5(x: Int): Int = if (x >= 5) x else None
// OK def notLessThan5(x: Int): Option[Int] = if (x >= 5) Some(x) else None Выполнение 2-го условия: // Ошибка компиляции: мы не учли, что notLessThan5() может не вернуть результата (вернуть None) println(notLessThan5(10) + notLessThan5(3))
// OK println(notLessThan5(10).getOrElse(5) + notLessThan5(3).getOrElse(5)) // напечатает 15 Во всех случаях соблюдение правильных принципов работы со значениями null проверит за нас компилятор, не допустив, чтобы NullPointerException "всплыла" в самый неподходящий момент во время эксплуатации программы. Проблемы null решены. Следует особенно заметить: мы не отказываемся от использования null. Мы просто интегрируем этот null в систему типов иначе, чем это сделано сейчас, в Java и им подобных. None, Nothing и проч. - есть точные эквиваленты null, только интегрированные в систему типов. Динамические языки программирования не используют преимущества статической типизации, поэтому все, что описано выше, их не касается. Избежать тех проблем, о которых говорил Хоар, в динамических языках нельзя в принципе - любая функция может вернуть ЛЮБОЕ значение. Это касается не только null, но вообще любых значений. Поэтому умные люди, которые используют динамические языки в повседневной практике, давно уже описали в литературе защитные практики от гибкости динамических языков. Основной практикой, помимо дисциплины и документации, является повсеместное и всеобъемлющее тестирование кода, причем как можно раньше, в идеале, до написания самого кода (TDD). Чудес не бывает: верификацию при проверке типов приходится заменять верификацией при тестировании. На эту тему рекомендую послушать великолепный доклад Robert Martin'а, произнесенный на RailsConf'09, "What Killed Smalltalk Could Kill Ruby, Too"