“По — функционален” Swift — първа част

Yasen Yankov
paysafe-bulgaria
Published in
4 min readMar 27, 2018

Функционалното програмиране е “гореща тема” напоследък, но какви са позитивите от изпозлването на функционален стил при писането на софтуер? Все пак подобни резултати бихме могли да постигнем и с ООП или с процедурен код. Страницата в Уикипедия дава бегла представа, но не достатъчно информация около позитивите и негативите на функционалното програмиране. Посреща с термини като ламбда смятане, функции от по-висок ред и списък от екзотични и непознати за повечето хора програмни езици като Lisp, Scheme и Clojure. Изводът, който повечето хора биха си направили е, че функционалното програмиране е нещо което се използва за решаване на специфична сфера от проблеми чрез програмни езици, създадени специално за тази цел.
В няколко блог статии ще се опитаме да покажем как функционалното програмиране би ни било полезно в ежедневната работа при създаването на нашите мобилни приложения.

Функционално програмиране

“Функционалното програмиране е начин за съставяне на програми, при който единственото действие е обръщението към функции, единственият начин за разделяне на програмата на части е въвеждането на име на функция и задаването за това име на израз, който пресмята стойността на функцията, а единственото правило за композиция е суперпозицията на функции. Тук под функция се разбира програмна част, която “връща” резултат (по-точно, във функционалното програмиране се работи с т. нар. строги функции, които не предизвикват никакви странични ефекти, а само връщат стойности).”

проф. Мария Нишева, ФМИ, Софийски Университет

От горната дефиниция, както и от страницата в Уикипедия, за която споменахме по-рано, можем да извадим няколко полезни принципа. Те биха могли да намерят приложение в ежедневната ни работа, а именно — immutability (неизменяемост), липса на състояние (state), модулност (композиция) и експресивност.

Immutability (неизменяемост)

В програмирането immutable обект е такъв обект, който след създаването си не може да бъде променян. На пръв поглед това може да не изглежда като много полезно, защото основната цел на обектите е да съхраняват данни и невъзможността да ги променяме ограничава това, но в действителност се оказва ценно свойство. Знаейки че един обект е неизменяем ни гарантира, че той е винаги валиден след като сме го създали. Също така можем да го подаваме като параметър навсякъде дори и да не сме напълно наясно с имплементацията на дадена функция, защото той не може да бъде променен.
Създаването на immutable обекти в Swift е много лесно, достатъчно е да декларираме променливата с let и нейната стойност не може да бъде променяна. А ако тя е от тип “структура (struct)”, то и полетата на структурата няма да могат да бъдат променяни.

struct Point {
var x, y: Float
}
let p = Point(x: 10, y: 5)
p.x = 5 // compiler error

Липса на състояние (state)

Понякога се налага да създаваме private property на някой обект, което се използва за предаване на данни между различните му методи. В началото всичко е подредено, знаем къде го променяме и къде го използваме след това. Но постепенно добавяме нови и нови отговорности към него, става все по-трудно да разберем къде това property се изменя и по какъв начин това влияе на всичко останало. Това довежда до така наречените “странични ефекти (side effects)”. За това във функционалното програмиране дефинираме чисти функции (pure functions), те приемат аргументи, обработват ги и връщат резултат. Не пазят състояние и дават предвидимост. Една чиста функцията при едни и същи аргументи ще върне еднакъв резултат при всяко извикване.

Модулност (композиция)

Много по-лесно е да пишем функции, които вършат само едно нещо. По-лесно е да ги тестваме и поддържаме, по-лесно ще и за този, който ще чете кода след нас. След това ги композираме в по-сложни и по-сложни функции, точно както части на конструктор. По този начин ако нещо не работи по начина, по който очакваме, по-лесно може да открием къде е проблемът. Друго предимство на този подход е, че малките функции са много по-универсални и могат да бъдат преизползвани и на други места.

Експресивност

“Express what we want to achieve, rather how it is implemented”

Javier So

Когато решаваме дадена задача ние искаме да изразим ясно нашата идея, а не начина, по който я постигаме. Нека за пример да сумираме квадратните корени на масив от числа. Стандартно бихме решили тази задача по следния начин:

let numbers = [4, -5, 16, 9, 0, -9]
var sum = 0
for number in numbers {
if number > 0 {
sum = sum + sqrt(number)
}
}

Като използваме функционален подход с някои от функциите, с които ще се запознаем в следващата част, можем да я напишем по следния начин:

let numbers = [4, -5, 16, 9, 0, -9]
let sum = numbers.filter({ $0 > 0 }) // избираме само положителните числа
.map( { sqrt($0) }) // пресмятаме квадратните им корени
.reduce(0, +) // сумираме ги

По този начин демонстрираме всичките принципи, които изброихме по рано:

  • Неизменяемост и липса на състояние — ие запазваме променливи с временен резултат, които някой може да промени или използва по начин, който не е желателен;
  • Модулност — използваме прости функции комбинирани по начин който решава нашата задача;
  • Експресивност — стъпките които правим, за да решим задачата, се виждат ясно, не са смесени с логиката и са разбираеми и четими от трето лице.

В следващият ни пост по темата ще се запознаем с начина, по които можем да пишем на Swift “по-функционално” в повече детайли. Stay tuned… :)

--

--

Yasen Yankov
paysafe-bulgaria

VP of Product Development @ Nexo, Ex — Head of Engineering @ PaySafe, Cryptocurrencies https://paysafe.com