しがない学生エンジニアのいぬしばです。
今回の記事はswfitの言語のパラダイム(考え方)について、自分なりにまとめます。
できるだけ専門的な用語を使わず、分かりやすさを心がけます。
有識者の方はぜひ指摘のコメントをしてください
目次
序章
ここではこの記事を読む準備をしてもらいます。
swift言語の概要
もしかしたら「swiftってなんぞや」って人がいるかもしれないのでここで軽く説明を...
swiftはAppleが開発した、Appleのソフトウェアを高速で安全に動かすための言語です。
元々はObjective-cでしたが、それをより簡単に分かりやすく書けるswiftができました。
Objective-CはC言語の構文を基本とした元祖apple製品開発言語です。
2014年のswift登場からの躍進によって今ではほとんど推奨されない。
しかしながら1983年から役30年支えただけあってそのドキュメントは多く、今なおサポートは終了していない。
パラダイムとは
もしかしたら「パラダイムってなんぞや」って人がいるかもしれないのでここで軽く説明を...
パラダイムとは要は言語における考え方です!この言語は関数型言語が適しているとか、オブジェクト指向に沿った書き方がいいだとか。
必ずしもそのパラダイムに沿わなくても動くのですが、頼むから従ってくれ!って感じです。
この話を初心者の僕がするのは気が引けるのですが、しっかし僕の現状の意見を述べて参ります!
以下よくあるパラダイムの例
↓↓
- オブジェクト指向(OOP)
- 関数型言語
- 手続き言語
- 命令型言語
- 宣言型言語
- 論理型言語
この記事の必要性
序章の最後に記事のこの記事の説明を行います。
まず僕自身の目的としては三つの目的があります。
- パラダイムを勉強してる人への助けを少しでもしたい
- 勉強した内容のアウトプット
- 有識者からの意見を受けること
1.Swiftのパラダイムってなに?
結論から言うと、swiftは複数個のパラダイムを使い分けることができます!
- オブジェクト指向(OOP)
- 関数型言語
- 手続き言語
- 命令型言語
- 宣言型言語
- 論理型言語
これらがswiftでできる一部のパラダイムなのですが、お気づきだろうか
swiftは大体のパラダイムを実現できます。
というのも、最近の言語はもう大体のパラダイムを使うことができます。
富 実績 力 この世の全てを手に入れた海賊王モダンパラダイム・ロジャー 彼の一言は人々を設計図への海へと駆り立てた 「俺のパラダイムか?使いたければ使え!この世の全てをそこ(構文)においてきた」ジャンジャーン ジャン ジャージャジャジャ(BGM) エンジニアたちは処理に適したパラダイムを目指し 最適解を追い続ける 世はまさに 大パラダイム時代!!!
補足の通り、最近の言語が複数のパラダイムを持つ理由は処理に合った、分かりやすいコーディングを行うためです。
簡単な例をswiftで出します
目標:Int配列内の要素の合計を出力
- 命令型
ただただ処理を並べて順番に実行
var total: Int = 0
let nums:[Int] = [0, 1, 100, 20, 30]
for i in nums {
total += i
}
print(total)
- 宣言型
何をしたいか、それだけ
let nums: [Int] = [0, 1, 100, 20, 30]
let total = nums.reduce(0, +)// ここで合計するどんな処理かはわからないが何をしたいかはわかる。
print(total)
SwiftのOOPにおけるアプローチ
まずオブジェクト指向(OOP)の原則について説明します。
オブジェクト指向を構成する三つの要素
- カプセル化
- 継承
- ポリモーフィズム
オブジェクト指向とは、システムのプログラムを一つのオブジェクト(物体)として扱うパラダイムです。
具体的には上記三つの構成を示しています。
カプセル化
カプセル化とは、物体を外的要因から守ることです。
では、ボールがありますよね、色々なサイズのボールです、野球ボールです。
この野球ボールは、外側から力を受けたらすごい速度で飛びますよね、しかし外的要因のせいでボールのサイズを変えてしまってはいいのでしょうか?ダメですよね、ボールのサイズは規格で決まってますのでサイズの変更は原則違反です(事故は除く)。
システムも一緒です、外側からなら影響受けていい部分とダメな部分があります、それらを安全に管理するパラダイム、それがカプセル化です。
継承
継承とは、物体の実装の引き継ぎです。
たとえば、ソフトボールを作りたいと思った時、既存の野球ボールの素材や材質を参考にすれば作りやすくなると思いませんか?
システムでもそれが可能です、既存のオブジェクトコードにツギハギした新しいオブジェクトコードを少ないコードで実装可能です。
ポリモーフィズム
ポリモーフィズムとは、物体の構造の引き継ぎです。
たとえば、ソフトボールを作りたいとき、既存の野球ボールの役割や意図を参考にすれば作りやすくなると思いませんか?
システムでもそれが可能です、既存のオブジェクトコードと同じ構成の新しいオブジェクトコードを少ないコードで、実装可能です。
swiftにおける三つの柱へのアプローチ
ではswiftではこの三つをどのように実現しているのでしょうか
以下のコードを見てほしい
class Ball {
private var size = 20
private var x: Int
private var y: Int
private var vX: Int = 10
private var vY: Int = 10
init(_ x: Int, _ y: Int) {
self.x = x
self.y = y
}
var currentX: Int {
return x
}
var currentX: Int {
return x
}
func moveBall() {
x += vX
y += vY
}
func bounceX() {
vX *= -1
}
func bounceY() {
vY *= -1
}
}
このコードにおいて、
private var size: Int = 100
private var x: Int
private var y: Int
private var vX: Int = 10
private var vY: Int = 10
の部分はclass外では読み込まれないが、
init(_ x: Int, _ y: Int) {
self.x = x
self.y = y
}
var currentX: Int {
return x
}
var currentX: Int {
return x
}
func moveBall() {
x += vX
y += vY
}
func bounceX() {
vX *= -1
}
func bounceY() {
vY *= -1
}
の部分はクラス外から、実行できる。
これはクラスのインスタンス値を適切に管理できるカプセル化を表現できています
それでは形を変えて、
class Ball {
省略
}
class SnowBall: Ball {
override func moveBall() {
super.moveBall()
size += 1
}
}
class IceBall: Ball {
override func moveBall() {
super.moveBall()
size -= 1
}
}
上記は、雪玉と氷玉を表すクラスを描きました。
両方ともボールクラスの機能に機能を加える必要があるので、継承を使っています。
swiftはclass+継承を推奨していません、あくまで可能というだけです。
また、適切な状況の時はもちろん使いましょう。
swiftはclass+継承を使うのではなくstruct+protocolを推奨しています
(のちに詳しく記述)
それでは次はポリモーフィズムの例を見て行きます。
通常、ポリモーフィズムを使う際はinterfaceを使用するのですが、
swiftではprotocolという新しいものを使います、機能はかなり似ているので怯えないでね。
protocol BallProtocol {
var currentX: Int { get }
var currentY: Int { get }
func moveBall()
func bounceX()
func bounceY()
}
class NormalBall: BallProtocol {
private var x: Int
private var y: Int
private var vX: Int = 5
private var vY: Int = 5
init(x: Int, y: Int) {
self.x = x
self.y = y
}
var currentX: Int {
return x
}
var currentY: Int {
return y
}
func moveBall() {
x += vX
y += vY
}
func bounceX() {
vX *= -1
}
func bounceY() {
vY *= -1
}
}
使い方はinterfaceと一緒ですが、プロトコルは構造を指定します。
プロトコルに準拠すればそれと同じ構造を撮ることができます
クラスの実装を受け継ぐことを継承するといい、プロトコルを使うことを準拠すると言います。
しかし、プロトコルが他のプロトコルの構造を受け継ぎたいときは継承すると言います。
あくまで準拠は構造に基づくという意味ですので、受け継ぐ場合は継承です。
また、クラスの継承はもちろんクラス同士でしか受け継げませんが、プロトコルの準拠はクラスに限らずstruct(構造体)にもできます。
swiftのOOPに対するアプローチは、全て可能です。
しかしswiftはclass+継承を推奨していません、なぜなら継承は安全でなく複雑な設計の開発下でコードの変更を行うと、予期せぬ動作を引き起こす可能性が増えるからです。
その代わりstruct+protocolの使用を推奨しています。
structは値型です。具体的に言えば、中身の値が変更された時、classのように内部(箱の中身)が変わるだけではなく、そもそも箱も新しくなるということです。これによってコードの挙動が予測しやすいのです。なぜなら、どう足掻いても同じものを参照することがなく、予期せぬ変動が減るから(逆に変動して欲しい時はclassを使用してください)。
また、protocolは「どのような機能を持つか」を定義する仕組みであり、前述の通りかなり柔軟に継承、準拠が可能で、struct,class以外にも型(IntやStringなど)の拡張機能や共通化で活躍します。
Optionalについて
それは10億ドルにも相当する私の誤りだ。null参照を発明したのは1965年のことだった。(中略)
これは後に数え切れない過ち、脆弱性、システムクラッシュを引き起こし、
過去40年間で10億ドル相当の苦痛と損害を引き起こしたとみられる。
null参照 (多くの言語で nil や null と呼ばれるもの)を発明したトニー・ホーアは次のように述べています
要はnullはとても危ないものであると
Optionalはこのように使います
let result: Int?
if let a0 = a {
result = a0 * a0
} else {
result = nil
}
このコードは、resultはintまたはnullを代入できるという意味で、要は初期化要らず、変数が空白でも扱えるということです。
これで、nullを変数として使える!!という機能でなはないです。
実際は
let a: Int? = 3
let a: Optional<Int> = 3
これらは同じ意味で、つまりはOptionalでintをラッパーしている状態です。
もし、Optionalでラッパーしたあとにその中身を使いたい時は、一度アンラップしてから使わなければいけない。
let result: Int?
if let a0 = a {
result = a0 * a0
} else {
result = nil
}
これは、一度a0=aで値が存在するかしないかをチェックする。
これによって値をとてもセキュアに動かせることができます!!。
Optionalではラップされたまま値を変更することもできます。
.mapや.flatMapなどならできます。
まとめ
swiftは混合パラダイムの中でもかなり新しい機能を入れた言語です。
ここには書ききれませんでしたが、swiftUIやUIkitなどのUIフレームワークもとても書きやすく楽しいです。以上、swiftでしたー
読んでくれた方はぜひ感想を書いてください!