Краткий обзор возможностей абстракции в компьютерном программировании.

Введение

Символы, код, по своей природе — код абстрактен. Вы можете сделать что-то из ничего с помощью кода, который является частью красоты и искусства создания отличного кода. За годы написания кода и работы над крутыми проектами и потрясающими вещами я многое узнал о том, как разные подходы, парадигмы и общие концепции применимы к разным сценариям. Одна концепция, силу которой я недавно ощутил, — это абстракция. Есть несколько причин, по которым абстракция сама по себе так полезна для создания действительно фантастического кода.

Как и следовало ожидать, сегодня мы покажем, как абстракция обычно применима к Джулии. Конечно, многие из этих концепций являются немного общими, и многие современные языки имеют свою собственную уникальную версию подтипирования, отличную от Julia, но во многих случаях другие языки можно сделать очень похожими на код, который я продемонстрирую для Юлия. Без дальнейших церемоний, давайте углубимся в причины, по которым я считаю абстракцию таким невероятным инструментом для обеспечения хорошей работы программного обеспечения. Если вы хотите просмотреть записную книжку, в которой есть немного кода из этой статьи, вот ссылка на записную книжку, которую я использовал для тестирования кода, представленного в этой части:



Супертипы

В Джулии концепция абстракции полностью вращается вокруг чего-то, называемого супертипами. Супертипы в Julia — это типы, которые не имеют полей, но вместо этого описывают название категории. Это позволяет нам назвать несколько типов и отнести их к категории. Мы можем создать такой тип в Julia, используя ключевые слова абстрактного типа. Насколько мне известно, ключевое слово type больше не используется ни для чего, кроме этого.

abstract type Hello end

Нам также нужно закончить эту фразу. Чтобы на самом деле использовать этот супертип, мы используем оператор подтипа ‹:. Этот оператор имеет цели; во-первых, он может сказать нам, является ли данный тип подтипом данного супертипа:

Int64 <: Integer
true

Другое использование фактически обозначает супертипы для конструкторов. Мы просто добавляем оператор и супертип в конструктор, например:

struct Example <: Hello
end

Это позволяет работать с несколькими типами, как если бы они были подтипами — по крайней мере, всякий раз, когда мы действительно хотим, чтобы они были таковыми. Излишне говорить, что это может быть довольно мощно, но почему именно оно настолько мощно?

Зачем использовать абстракцию?

Давайте кратко поговорим о том, что такое абстракция и почему она может быть так полезна. Абстракция — это метод программирования, который позволяет нам классифицировать различные вещи, чтобы определить, какие другие части нашего кода могут с ними взаимодействовать. В результате получается несколько разных вещей, которые здорово иметь в своем коде.

Меньше кода

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

mutable struct Dog
   weight::Int64
end
mutable struct Cat
   weight::Int64
end

Если бы мы хотели создать метод для этих двух, мы могли бы оставить отправку невероятно открытой, предоставив либо вершину иерархии типов, супертип Any, либо не аннотируя; который автоматически предполагает, что тип Any.

function gain_weight!(animal::Any)
    animal.weight += 5
end

Этот метод хорошо работает как для кошек, так и для собак.

cat = Cat(55)
dog = Dog(80)
gain_weight!(cat)
println(cat.weight)
60

Однако этот метод также может принимать всю иерархию типов, что означает, что этот пример не приведет к ошибке метода, но приведет к ошибке.

gain_weight!(5) # <- Of type Int64

Когда это происходит, мы получаем ошибку, потому что 64-битное целое не имеет веса поля. Мы можем ограничить типы, которые здесь передаются, создав абстрактный тип (также называемый супертипом).

abstract type Animal end

Затем мы можем наследовать все методы, отправленные в Animal, путем подтипирования наших типов.

mutable struct Dog <: Animal
   weight::Int64
end
mutable struct Cat <: Animal
   weight::Int64
end
function gain_weight!(animal::Animal)
    animal.weight += 5
end

Неопределенные типы

При работе с огромными проектами, обычно проектами с большим количеством включений/экспортов, существует тенденция сталкиваться с ошибками загрузки из-за того, что определенные вещи не определены до загрузки других вещей. При работе с большими проектами вполне возможно, что вы можете загрузить функцию, которая отправляется в тип, который еще не загружен. Абстрактные типы могут помочь избежать этой распространенной ловушки, сохраняя определения типов и ссылки на них абстрактным способом, а затем определяя новые типы как аналогичные созданному нами абстрактному определению.

Заключение

Абстракция в Julia невероятно полезна и действительно может улучшить качество вашего кода. Конечно, Julia — не единственный язык с этим свойством, но, безусловно, это отличный пример языка, в котором эта концепция может использоваться невероятно эффективно. Абстракция в Джулии позволяет сократить код до четверти его исходного размера, и это то, что я определенно рекомендую использовать. Большое спасибо, что прочитали мою статью, она значит для меня мир. Надеюсь, абстракция появится в будущем проекте, и вы сможете вернуться к этой статье, чтобы пройти через это!