Комментарии 10
В любой программе на Julia можно доопределить собственные типы данных, и работа с ними от работы со встроенными почти ничем не отличается ни с точки зрения написания кода, ни с точки зрения скорости исполнения этого кода (привет, Python).
приехали, то есть всё равно что в Julia статическая типизация и можно спокойно то же самое на Питоне писать, зная что примерно с такой же скоростью будет?
производительность кода, который аннотирован типами, приближается к компилируемым языкам
Тут лучше уточнить. Дело не в аннотациях, а в стабильности типов. Например, в статье используется функция ∈ из стандартной библиотеки. В её определении нет ни одной аннотации типа. При её первом вызове на аргументах новых типов — в данном случае, Int64 и Deque{Int64} — JIT-компилятор подготовит машинный код. Поскольку тело этой функции позволяет компилятору статически определить по типам её аргументов типы всех промежуточных значений (именно это свойство называется "стабильностью"), этот машинный код не будет содержать диспетчеризации, и должен примерно соответствовать по производительности аналогичному коду на C++.
Так я и говорю, что в Julia пользовательские типы так же быстро будут работать, как встроенные (привет, Python, когда тебе такое завезут?).
А типизация там всё-таки динамическая, вот пример:
function f(x::Int)
x = string(x)
x^2
end
julia> f(1)
"11"
То есть вышеупомянутое будет
function f(x::Int)
string y = string(x)
y^2
end
то есть статической тип, потому что известно в компайлтайме
Карпински говорит, что типизация динамическая.
Пример я специально такой привёл — хотя в сигнатуре функции указано, что x
— это Int
, в теле функции он может поменять тип. В отличие от Си, например, где имя формального аргумента в теле функции привязано к типу.
Есть и статические определения типов переменных — например
function f(x::Int)
x::Int = x
x = string(x)
x^2
end
будет падать при вызове, потому что к x
теперь уже в теле функции прицеплен тип Int
.
Но это всё равно не совсем статическая типизация — т.к. при статической типизации ошибка должна выскочить на этапе компиляции, а не при вызове.
Я не знаю, правда, совместимы ли статическая типизация и eval()
...
Говорят, на JVM есть соответствующие средства в ассортименте: Scala, Kotlin, Java. Но тут вопрос, считать ли все эти трюки с Object всё ещё статической типизацией. Мне кажется, что всё-таки можно, если значение вот так сразу приводится к конкретному типу и дальше следующей строчки как Object не живёт.
function f(x::Int)
// до присвоения, x is int
x = string(x)
//могло бы разруливаться как string y = string(x)
и далее y вместо x, то есть как статическое, но так судя по всему не делают…
Можно извратиться и так, что при компиляции принципиально вывести ничего нельзя. Например:
function f(x::Int)
x = rand(Bool) ? x : string(x)
x^2
end
И ничего, работает. Предвосхищая вопросы: специально так стараются не писать. Более того, стараются писать именно так, чтобы статический вывод типов работал. Но в целом, язык разрешает на это не обращать особого внимания.
> неявная
Это тяжело назвать неявной типизацией, поскольку, если опустить тип, то он не выводится, а скорее для каждого конкретного типа в рантайме будет генерироваться новая функция. Что-то похожее на `C++ auto`, только с монорфизацией в рантайме.
Julia: пользовательские типы