Есть ли способ явно требовать от Юлии (например, в рамках модуля или пакета), что типы должны быть объявлены ? Есть ли , например , PackageCompiler
или Lint.jl
есть какая - либо поддержка для таких проверок? В более широком смысле, предоставляет ли стандартный дистрибутив Julia какой-либо статический анализатор кода или аналог, который может помочь проверить это требование?
В качестве мотивирующего примера, скажем, мы хотим убедиться, что наша растущая база производственного кода принимает только код, который всегда объявляется типом , в соответствии с гипотезой, что большие базы кода с объявлениями типов имеют тенденцию быть более удобными для сопровождения.
Если мы хотим применить это условие, обеспечивает ли Julia в своем стандартном дистрибутиве какие-либо механизмы, требующие объявления типа, или помогает в достижении этой цели? (например, что-нибудь, что может быть проверено с помощью линтеров, хуков коммитов или эквивалентного?)
источник
hasmethod(f, (Any,) )
вернется,false
если родовое определение не было определено. Вы все равно должны соответствовать количеству аргументов (то естьhasmethod(f, (Any,Any) )
для функции с двумя аргументами).Ответы:
Краткий ответ: нет, в настоящее время нет инструментов для проверки типов вашего кода Джулии. Однако в принципе это возможно, и в прошлом в этом направлении была проделана определенная работа, но сейчас нет хорошего способа сделать это.
Более длинный ответ заключается в том, что «аннотации типов» здесь представляют собой красную сельдь, и вам действительно нужна проверка типов, поэтому более широкая часть вашего вопроса на самом деле является правильным вопросом. Я могу немного рассказать о том, почему аннотации типов являются красной сельдью, о некоторых других вещах, которые не являются правильным решением, и о том, как будет выглядеть правильное решение.
Требование аннотаций типов, вероятно, не достигнет того, чего вы хотите: можно просто поместить
::Any
любое поле, аргумент или выражение, и у него будет аннотация типа, но не та, которая говорит вам или компилятору что-нибудь полезное о фактическом типе этой вещи. Это добавляет много визуального шума, фактически не добавляя никакой информации.Как насчет необходимости конкретных аннотаций типа? Это исключает просто надевать
::Any
все (что в любом случае делает Джулия неявно). Тем не менее, существует много совершенно допустимых вариантов использования абстрактных типов, которые могут быть запрещены. Например, определениеidentity
функцииКакой конкретный тип аннотации вы бы поместили
x
под это требование? Определение применимо для любогоx
, независимо от типа - это своего рода точка функции. Единственная правильная аннотация типаx::Any
. Это не аномалия: есть много определений функций, которые требуют абстрактных типов, чтобы быть корректными, поэтому принуждение тех, кто использует конкретные типы, было бы весьма ограничивающим с точки зрения того, какой код Джулии можно написать.Есть понятие «стабильность типов», о котором часто говорят в Юлии. Этот термин, как представляется, возник в сообществе Julia, но был подобран другими динамическими языковыми сообществами, такими как R. Определить его немного сложно, но это примерно означает, что если вы знаете конкретные типы аргументов метода, Вы также знаете тип его возвращаемого значения. Даже если метод является стабильным по типу, этого недостаточно, чтобы гарантировать, что он будет проверять тип, потому что стабильность типа не говорит ни о каких правилах для принятия решения, проверяет ли что-то тип или нет. Но это идет в правильном направлении: вы хотели бы иметь возможность проверить, что каждое определение метода стабильно по типу.
Вы много не хотите требовать стабильности типов, даже если бы могли. Начиная с Julia 1.0, стало обычным делом использовать небольшие союзы. Это началось с изменения дизайна протокола итерации, который теперь используется,
nothing
чтобы показать, что итерация выполнена, а не возвращать(value, state)
кортеж, когда есть еще значения для итерации. Этиfind*
функции в стандартной библиотеке также использовать возвращаемое значение ,nothing
чтобы указать , что значение не было найдено. Это технически нестабильные типы, но они являются преднамеренными, и компилятор довольно хорошо рассуждает о том, как оптимизировать ситуацию вокруг нестабильности. Поэтому, по крайней мере, небольшие союзы, вероятно, должны быть разрешены в коде. Более того, нет четкого места, где можно провести черту. Хотя, возможно, можно сказать, что тип возвратаUnion{Nothing, T}
приемлемо, но не более непредсказуемо, чем это.Однако вам, скорее всего, действительно нужно, а не требовать аннотаций типов или стабильности типов, - иметь инструмент, который будет проверять, что ваш код не может генерировать ошибки метода, или, возможно, в более широком смысле, что он не будет генерировать какие-либо неожиданные ошибки. Компилятор часто может точно определить, какой метод будет вызываться на каждом сайте вызова, или, по крайней мере, сузить его до пары методов. Вот как он генерирует быстрый код - полная динамическая отправка выполняется очень медленно (например, намного медленнее, чем в vtables в C ++). Если вы написали неправильный код, с другой стороны, компилятор может выдать безусловную ошибку: компилятор узнает, что вы допустили ошибку, но не сообщит вам об этом до времени выполнения, так как это семантика языка. Можно потребовать, чтобы компилятор мог определить, какие методы могут быть вызваны на каждом сайте вызова: это гарантировало бы, что код будет быстрым и что нет ошибок метода. Вот что должен сделать хороший инструмент проверки типов для Джулии. Для такого рода вещей есть отличная основа, поскольку компилятор уже выполняет большую часть этой работы как часть процесса генерации кода.
источник
Это интересный вопрос. Ключевой вопрос заключается в том, что мы определяем как объявленный тип . Если вы имеете в виду, что
::SomeType
в каждом определении метода есть оператор, то сделать это несколько сложно, поскольку у вас есть разные возможности динамического генерирования кода в Julia. Может быть, есть полное решение в этом смысле, но я не знаю его (я хотел бы узнать это).Однако мне приходит в голову мысль, что сделать это относительно просто - проверить, принимает ли какой-либо метод, определенный в модуле, в
Any
качестве аргумента. Это похоже, но не эквивалентно предыдущему утверждению как:выглядят одинаково для
methods
функции, поскольку подпись обеих функций принимаетx
какAny
.Теперь, чтобы проверить, может ли какой-либо метод в модуле / пакете принять
Any
в качестве аргумента какой-либо из методов, определенных в нем, можно использовать что-то вроде следующего кода (я не тестировал его всесторонне, так как только что записал, но, похоже, в основном охватите возможные случаи):Теперь, когда вы запускаете его на
Base.Iterators
модуле, вы получаете:и когда вы, например, проверяете пакет DataStructures.jl, вы получаете:
То, что я предлагаю, не является полным решением вашего вопроса, но я нашел его полезным для себя, поэтому подумал поделиться им.
РЕДАКТИРОВАТЬ
Приведенный выше код принимает
f
бытьFunction
только. В общем, вы можете иметь типы, которые могут быть вызваны. Затемcheck_declared(m::Module, f::Function)
сигнатура может быть изменена наcheck_declared(m::Module, f)
(на самом деле тогда сама функция разрешитAny
в качестве второго аргумента :)) и передать все оцененные имена в эту функцию. Тогда вам нужно будет проверить,methods(f)
имеет ли положительное значениеlength
внутри функции (какmethods
для не вызываемых, возвращает значение, которое имеет длину0
).источник