Swift 정리 - Swift란?


Swift가 무엇인지 알아보자.


image

애플은 iOS, macOS, watchOS, tvOS 등 자사 제품 개발에 활용하기 위해 새 프로그래밍 언어인 Swift를 만들었다. 기존 애플 운영체제용 언어인 Objective-C와 함께 사용할 용도로 만들어진 것이다.

image

위 사진은 Apple Developer 페이지에 Swift를 소개한 문구를 가져온 것이다.

애플의 Swift 소개글에서 확인할 수 있듯이, Swift는 여러 장점을 지니고 있다.

최신 기능

Swift는 프로그래밍 언어에 대한 최신 연구 결과답게 미래 지향적인 개념을 내포하고, 많은 최신 기능들을 가지고 있다.

  • 강력하고 사용이 간편한 제네릭
  • 프로토콜 extension으로 보다 쉬워진 제네릭 코드 작성
  • 1급 함수 및 가벼운 클로저 구문
  • 범위 또는 컬렉션에서의 빠르고 간결한 반복
  • 튜플 및 멀티플 반환 값
  • 메소드, 확장 프로그램 및 프로토콜을 지원하는 구조
  • 페이로드를 포함할 수 있으며 패턴 일치를 지원하는 enum
  • 함수형 프로그래밍 패턴(예:지도 및 필터)
  • try/catch/throw를 사용한 기본 오류 처리

안전 중심 설계

Swift는 여러 방법으로 불안정성을 없앤다. 변수는 항상 사용전 초기화를 하고, 배열/정수에 대해 오버플로우 검사를 하고, 메모리는 자동으로 관리한다. 또한 옵셔널 타입이라는 것이 존재해 옵셔널 타입이 아닌 변수에는 절대로 nil 값이 할당되지 않도록 보호한다.

Swift는 컴파일 언어로, 컴파일 시에 이런 불안정성을 검사해서 런타임에 발생할 수 있는 오류를 사전에 방지한다.

빠르고 강력한 성능

Swift는 Objective-C와 같이 LLVM(Low Level Virtual Machine, 컴파일러의 기반 구조로 컴파일, 링크, 런타임에서 프로그래밍 언어에 상관없이 최적화를 쉽게 할 수 있도록 구성됨)으로 빌드되고 같은 런타임을 공유한다.

소스 및 바이너리 호환성

Swift는 오픈소스이다. 또한 Swift는 크로스 플랫폼을 지원하며, Linux를 비롯한 모든 애플 플랫폼을 지원한다. Swift는 애플 플랫폼 뿐만 아니라 서버 응용 프로그램에도 사용된다.

위에 언급한 장점들 외에도 Swift는 여러 장점들을 가지고 있다. Swift의 목표는 시스템 프로그래밍, 모바일 앱에서 데스크탑 앱, 그리고 클라우드 서비스까지 사용할 수 있는 최적의 언어가 되는 것이다. 가장 중요한 것은 개발자들이 올바르고, 쉽게 코드를 작성할 수 있도록 하는 것이다. 이런 목표를 위해 Swift는 아래와 같은 특징들을 가지고 있다.

Swift의 언어적 특성

Swift.org의 Swift 소개글을 보면 아래와 같이 세 가지 특징으로 Swift를 소개하고 있다.

image

바로 Safe, Fast, Expressive이다.

Safe

Swift는 안전한 프로그래밍을 지향한다. 개발 도중 프로그래머가 할 수 있는 실수를 엄격한 문법을 통해 방지한다. 이런 문법은 비록 강제적이라고 느껴질 수도 있지만, 문법으로 규제된 분명함이 소프트웨어를 더 오래 지속되게 만들어준다. 옵셔널, guard문, 오류처리, 강력한 타입 통제 등을 통해 Swift는 안전한 프로그래밍을 구현하고 있다.

Fast

Swift는 C 기반 언어 (C, C++, Objective-C)를 대체하기 위해 작성된 언어이다. 따라서 C 기반 언어들을 사용했을 때의 성능과 같은 성능을 유지해야 한다. 실행 속도의 최적화뿐만 아니라 컴파일러를 지속적으로 개량해 더 빠른 컴파일 성능을 구현해 나가고 있다.

Expressive

컴퓨터 과학 분야의 발전과 함께 성장한 수많은 프로그래밍 언어마다 문법은 조금씩 다르고, Swift는 이를 참고해 개발자들이 기대하는 최신 기능과 함께 사용하기 좋은 문법을 제공한다. 하지만 여기에서 멈추지 않고 언어들의 발전을 모니터링해서 Swift는 더 발전될 것이다.

이 “Expressive”하다는 특징은 즉 개발자들이 사용하기 좋은 문법과 최신 기능을 제공한다는 뜻이 될 것이다.

패러다임

Swift는 여러가지 프로그래밍 패러다임(간단히 프로그래밍 스타일을 의미한다.)을 채택한 다중 패러다임 프로그래밍 언어다. Swift는 명령형과 객체지향 프로그래밍 패러다임을 기반으로 한 함수형 프로그래밍 패러다임과 프로토콜 지향 프로그래밍 패러다임을 지향한다.

image

함수형, 프로토콜 지향 프로그래밍 패러다임이 뭔지 알아보기 전에 먼저 명령형 패러다임과 객체지향 패러다임을 알아보자.

명령형 패러다임

명령형 패러다임은 선언형 패러다임과 대비되는 패러다임으로, 프로그램의 상태를 변경하는 구문의 관점에서 연산을 설명하는 패러다임이다. 처음에 바로 이해하기가 어려운데, 즉 연산이 프로그램의 상태를 변화시키는데, 이 연산들(명령)은 컴퓨터가 작업을 어떻게 처리할지를 표현한 것이다. 따라서 명령형 프로그램은 컴퓨터가 수행할 명령들을 순서대로 써놓은 것이다.

대부분의 컴퓨터 하드웨어는 명령형으로 구현된다. 이 하드웨어들은 기계어를 실행하는데, 기계어가 명령형으로 작성되어 있다. 명령형 프로그래밍은 요리법에 빗댈 수 있는데, 각 단계별로 지시 사항이 있고, 변하는 상태들은 현실에 반영된다.

선언형 프로그래밍?

위에서 명령형 프로그래밍은 선언형 프로그래밍과 대조되는 개념이라고 말했는데, 그렇다면 선언형 프로그래밍은 무엇일까? 선언형 프로그래밍은 프로그램이 무엇이라는 개념을 설명하고 있는 프로그래밍이다. 명령형 프로그래밍은 프로그램이 어떻게 해야한다를 설명하고 있지만, 선언형은 무엇이라는 걸 설명하는 것이다. 예를 들어 웹 페이지는 선언형인데, 웹페이지는 글꼴, 제목, 사진과 같은 무엇을 화면에 출력해야할지를 설명하지, 어떤 방법으로 이것들을 화면에 출력해야 할 지 설명하지 않는다.

위의 내용들을 정리하면 아래와 같다.

  • 명령형 : HOW (ex 12번 테이블 자리가 비어있다. 나는 저기로 걸어가서 앉을 것이다.)
  • 선언형 : WHAT (ex 1명 앉을 자리를 준비해주세요.)

참고로 명령형과 선언형 프로그래밍의 차이를 정말 알기 쉽게 작성한 블로그 글이 있어서 가져와봤다. (https://boxfoxs.tistory.com/430)

객체지향 패러다임 (OOP, Object Oriented Programming)

객체지향 프로그래밍 패러다임은 현대 프로그래밍 언어 대부분에서 차용하고 있는 패러다임으로, 프로그램을 명령어의 목록으로 보는 시각이 아닌 여러 개의 독립된 객체들의 모임으로 보는 것이다. 이때 객체들은 메세지를 주고받을 수 있다.

객체지향 프로그래밍은 프로그램의 수정을 용이하게 만들어서 대규모 소프트웨어 개발에 많이 사용된다. 객체를 잘 이해하면 개발과 유지보수를 간편히 할 수 있고, 직관적으로 코드를 분석할 수 있다. 소프트웨어 공학의 관점에서 소프트웨어의 질을 높이려면 강한 응집력과 약한 결합력을 지향해야 한다.

  • 강한 응집력 : 클래스에 하나의 목적을 위한 데이터, 메서드를 모아놓음으로써 응집력을 강화
  • 약한 결합력 : 각 클래스를 독립적으로 디자인 해 결합력을 약화

특징

  • 추상화 : 불필요한 정보는 숨기고, 중요한 정보만 표현해서 프로그램을 간단하게 만드는 것이다. 자료 추상화를 통해 정의된 자료형을 추상 자료형이라 하는데, 추상 자료형은 자료 표현과 연산을 캡슐화한 것으로 접근제어를 통해 자료형의 정보를 은닉한다.
    • 추상 자료형 : 클래스
    • 추상 자료형의 인스턴스 : 객체
    • 추상 자료형의 연산 : 메서드
  • 상속 : 새로운 클래스가 기존 클래스의 자료와 연산을 사용할 수 있게 한다. 상속을 통해 클래스 간의 종속 관계를 형성해 객체를 조직화 할 수 있고, 코드의 중복을 피할 수 있다.
    • 기존 클래스 : 상위 클래스, 부모 클래스, 기반 클래스
    • 새로운 클래스 : 파생 클래스, 하위 클래스, 자식 클래스, 부클래스
  • 다중 상속 : 클래스가 2개 이상의 클래스로부터 상속받을 수 있다. 클래스들의 기능이 동시에 필요할 때 유용하지만 상속 관계에 혼란을 줄 수 있다.
  • 다형성 : 한 요소에 여러 개념을 넣어놓은 것으로, 오버라이딩/오버로딩을 의미한다. 즉 각 요소(상수, 변수, 오브젝트, 함수, 메서드 등)이 다양한 자료형에 속하는 것이 허용되는 성질이다. 다형성을 통해 프로그램 내 객체간의 관계를 조직적으로 나타낼 수 있다.
  • 동적 바인딩 : 실행 시간 중에 일어나거나 실행 중 변경도리 수 있는 바인딩으로 컴파일 시간에 완료되어 변하지 않는 정적 바인딩과 대비된다. 프로그램의 한 개체/기호를 실행 과정 중 여러 속성/연산에 바인딩해서 다형 개념을 실현한다.

클래스와 객체

  • Class : 같은 종류(또는 문제 해결을 위한)의 집단에 속하는 속성과 행위를 정의한 것이다. OOP의 기본 사용자 정의 데이터 타입이라고 할 수 있다. 클래스는 다른 클래스/외부 요소와 독립적으로 디자인 되어야 한다.
  • Object : 클래스의 인스턴스(실제로 메모리에 할당된 것)다. 객체는 고유의 속성(attribute)을 가지며 클래스에서 정의한 행위(behavior)를 할 수 있다. 객체의 행위는 클래스의 행위의 정의를 공유해서 메모리를 경제적으로 사용한다. Swift에서는 객체라는 용어보다 “클래스의 인스턴스”라는 표현을 사용한다.(enum, struct의 인스턴스가 아닌 class의 인스턴스임에 주목하자.)
  • Method / Message : 클래스에서 생성된 객체를 사용하는 방법으로, 객체에 명령을 내리는 메세지라고 할 수 있다. 메서드는 한 객체의 subroutine 형태로 객체의 속성을 조작하는데 사용한다. 객체 간의 통신은 메세지를 이용해 이루어진다.

함수형 프로그래밍 패러다임

함수형 프로그래밍(functional programming)은 자료 처리를 수학적 함수의 계산으로 취급하고 상태와 가변 데이터를 멀리하는 프로그래밍 패러다임이다. 명령형 프로그래밍 패러다임에서는 상태를 바꾸는 것을 강조하는데, 함수형 프로그래밍은 함수의 응용을 강조한다.

수학적 함수와 명령형 프로그래밍에서 사용되는 함수에는 차이가 있는데, 수학적 함수(pure function)는 항상 같은 입력값이 주어지면 같은 결과가 나오고, 상태에 영향을 받지 않으며 부작용이 없다. 이는 명령형 프로그래밍에서 많이 쓰이는 impure procedures 가 프로그램의 상태를 상태를 변화시키거나 사용자에게 입력값을 받는 등의 부작용을 가진 것과 대조된다. 이런 purely functional programming의 장점은 부작용을 제거해서 프로그램이 더 적은 버그를 가지고, 디버깅하고 테스트하기 쉽게 해주는 것이다.

함수형 프로그래밍 패러다임은 최근 프로그래밍 패러다임의 대세로 떠오르고 있는데, 가장 큰 장점은 대규모 병렬처리가 굉장히 쉽다는 것이다. 그 이유는 프로그램이 동작할 때 상태(값)가 변하지 않으면 함수 호출이 서로 간섭 없이 배타적으로 실행되기 때문에 병렬처리할 때 부작용이 거의 없다. 프로세스나 스레드별로 특정 값을 참조하기 위해 락을 걸거나 대기할 필요가 없기 때문이다. 또한 필요한 만큼 함수를 나누어 처리할 수 있도록 스케일업 할 수 있기 때문에 대규모 병렬처리에 큰 강점이 있다.

함수형 프로그래밍의 다른 큰 특징은 함수를 일급 객체(First-class Citizen)로 다룬다는 것이다. 일급 객체는 아래의 조건을 만족해야 한다.

  • Argument로 전달할 수 있다.
  • 동적 프로퍼티 할당이 가능하다.
  • 변수나 데이터 구조 안에 담을 수 있다.
  • 반환 값으로 사용할 수 있다.
  • 할당할 때 사용된 이름과 관계없이 고유한 객체로 구별할 수 있다.

Swift의 함수는 위의 조건을 모두 충족하기 때문에 함수가 일급 객체로 취급된다. 함수가 일급 객체가 된다는 것은 다양한 종류의 함수를 호출, 전달, 반환하는 것만으로도 프로그램을 구현할 수 있다는 것이다.

Imperative vs Functional programming

실수로 주석에 #을 사용했는데 무시하고 봐주길 바란다.

명령형

image

함수형

image

위와 같이 함수는 일급 객체로 취급되기 떄문에 함수의 전달 인자나 반환 값으로 사용할 수 있다.

image

또한 위와 같이 여러 개의 매개변수를 갖는 함수를 매개변수 하나를 갖는 함수의 나열로 표현하는 Currying 기법을 사용해서 전달인자를 하나만 두고 함수를 반환하는 방식으로 전달 할 수 있다.

위에서 함수형 프로그래밍 패러다임을 설명할 때, 상태와 가변데이터를 멀리하기 때문에 부작용이 없다고 했다. 이 부작용이라는 게 무슨 말인지도 보자.

명령형

image

함수형

image

이제 명령형과 함수형의 차이를 정리하면 아래와 같다.

 명령형함수형
개발자의 초점작업 수행 알고리즘, 상태 변경 추적원하는 정보, 필요한 변환
상태 변경중요없음
실행 순서중요낮음
주요 흐름 제어제어 구문(반복문, 조건문), 메서드 호출순환(재귀) 호출 등의 함수 호출
주요 조작 단위클래스, 구조체의 인스턴스함수

스위프트가 함수형 프로그래밍 패러다임을 차용한 의의

프로그래밍 언어마다 어떤 프로그래밍 패러다임이 있다고 말하기 쉽지 않지만, 애플이 Swift를 공개하며 발표한 내용을 보면 Swift는 확실히 객체지향 프로그래밍 패러다임과 함수형 프로그래밍 패러다임을 모두 차용하고 있다.

애플의 프레임워크 대부분은 객체지향 프로그래밍 패러다임을 기반으로 설계된 클래스들로 구성되어 있기 때문에 애플의 프레임워크에서 사용될 언어가 객체지향 프로그래밍 패러다임을 수용하지 않는다면 문제가 생길 것이다.

함수형 프로그래밍 패러다임이 강조되는 이유는 애플의 프레임워크를 벗어나 다른 영역(서버 등)에서 스위프트를 사용했을 때 순수하게 함수형 프로그래밍 패러다임으로 프로그램을 작성할 수 있기 때문이다.

순수하게 함수형 프로그래밍 패러다임으로 프로그램을 작성하면 아래와 같은 장점이 있다.

  • 여러 가지 연산 처리 작업이 동시에 일어나는 프로그램을 만들기 쉽다.
  • 멀티 코어/여러 개의 연산 프로세서를 사용하는 시스템에서 효율적인 프로그램을 만들기 쉽다.
  • 상태변화에 따른 부갖용에서 자유로워지므로 순수하게 기능 구현에 초점을 맞춰 설계할 수 있다.

따라서 적절하게 객체지향과 함수형 프로그래밍 패러다임을 섞어 작성하면 성능도 챙기고 생산성도 챙길 수 있게 된다.

프로토콜 지향

Swift 2.0에서 추가된 프로토콜 익스텐션은 스위프트가 프로토콜 지향 언어가 되게끔 했다. WWDC에서 스위프트는 프로토콜 지향 언어라고 발표하기도 했고, 프로토콜 지향 프로그래밍은 참조 타입인 클래스의 인스턴스보다 값 타입을 더 효율적으로 사용하고, 오류를 줄일 방법이라 했다.

Swift에서는 구조체, 열거형에 클래스에서 구현할 수 있던 캡슐화, 추상화, 접근 제어 등의 기능을 모두 구현할 수 있다. 게다가 프로토콜에 익스텐션을 활용할 수 있어졌기 때문에 프로토콜 지향 프로그래밍이 가능해졌다. 이를 통해 참조 타입의 참조 문제에서 더 자유로워졌고, 다중상속이 불가능한 한계를 뛰어넘으며 더 나은 추상화 메커니즘을 구현할 수 있게 되었다.