From f25636f5ce6e090fae42087b061260d92319c0fa Mon Sep 17 00:00:00 2001 From: Stephen Celis Date: Mon, 14 Oct 2024 10:43:19 -0700 Subject: [PATCH] wip --- .../Contents.swift | 176 +++++++++ .../contents.xcplayground | 2 + .../project.pbxproj | 292 +++++++++++++++ .../contents.xcworkspacedata | 7 + .../BackToBasicsEquatable/main.swift | 11 + 0297-back-to-basics-equatable-pt1/README.md | 5 + .../Contents.swift | 341 ++++++++++++++++++ .../contents.xcplayground | 2 + .../project.pbxproj | 292 +++++++++++++++ .../contents.xcworkspacedata | 7 + .../BackToBasicsEquatable/main.swift | 11 + 0298-back-to-basics-equatable-pt2/README.md | 5 + README.md | 4 + 13 files changed, 1155 insertions(+) create mode 100644 0297-back-to-basics-equatable-pt1/BackToBasicsEquatable/BackToBasicsEquatable.playground/Contents.swift create mode 100644 0297-back-to-basics-equatable-pt1/BackToBasicsEquatable/BackToBasicsEquatable.playground/contents.xcplayground create mode 100644 0297-back-to-basics-equatable-pt1/BackToBasicsEquatable/BackToBasicsEquatable.xcodeproj/project.pbxproj create mode 100644 0297-back-to-basics-equatable-pt1/BackToBasicsEquatable/BackToBasicsEquatable.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 0297-back-to-basics-equatable-pt1/BackToBasicsEquatable/BackToBasicsEquatable/main.swift create mode 100644 0297-back-to-basics-equatable-pt1/README.md create mode 100644 0298-back-to-basics-equatable-pt2/BackToBasicsEquatable/BackToBasicsEquatable.playground/Contents.swift create mode 100644 0298-back-to-basics-equatable-pt2/BackToBasicsEquatable/BackToBasicsEquatable.playground/contents.xcplayground create mode 100644 0298-back-to-basics-equatable-pt2/BackToBasicsEquatable/BackToBasicsEquatable.xcodeproj/project.pbxproj create mode 100644 0298-back-to-basics-equatable-pt2/BackToBasicsEquatable/BackToBasicsEquatable.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 0298-back-to-basics-equatable-pt2/BackToBasicsEquatable/BackToBasicsEquatable/main.swift create mode 100644 0298-back-to-basics-equatable-pt2/README.md diff --git a/0297-back-to-basics-equatable-pt1/BackToBasicsEquatable/BackToBasicsEquatable.playground/Contents.swift b/0297-back-to-basics-equatable-pt1/BackToBasicsEquatable/BackToBasicsEquatable.playground/Contents.swift new file mode 100644 index 00000000..680a7bb2 --- /dev/null +++ b/0297-back-to-basics-equatable-pt1/BackToBasicsEquatable/BackToBasicsEquatable.playground/Contents.swift @@ -0,0 +1,176 @@ +//let x: any Equatable + +struct User: Equatable { + let id: Int + var isAdmin = false + var name: String + + static func == (lhs: Self, rhs: Self) -> Bool { + lhs.id == rhs.id && lhs.isAdmin == rhs.isAdmin && lhs.name == rhs.name +// lhs.id == rhs.id +// lhs.isAdmin == rhs.isAdmin && lhs.name == rhs.name + } +} + +let blob = User(id: 42, isAdmin: false, name: "Blob") + +let id42Partition = [ + User(id: 42, isAdmin: true, name: "Blob"), + User(id: 42, isAdmin: false, name: "Blob, Esq."), + User(id: 42, isAdmin: true, name: "Blob, Esq."), + User(id: 42, isAdmin: true, name: "Blob, MD"), + User(id: 42, isAdmin: true, name: "Blob, MD"), + // ... +] + +id42Partition.allSatisfy { lhs in + id42Partition.allSatisfy { rhs in + lhs == rhs + } +} + +struct Mod12: Equatable { + var value: Int + init(_ value: Int) { + self.value = value + } + + static func == (lhs: Self, rhs: Self) -> Bool { + (rhs.value - lhs.value).isMultiple(of: 12) + } + + func add(to other: Self) -> Self { + Self(value + other.value) + } + var isBig: Bool { + value >= 100 + } +} +func algorithm(lhs: Mod12, rhs: Mod12) { + let bothAreBig = lhs == rhs + ? lhs.isBig + : lhs.isBig && rhs.isBig +} + +do { + let three = Mod12(3) + let fifteen = Mod12(15) + Mod12(2).add(to: three) == Mod12(2).add(to: fifteen) + + Mod12(2) == Mod12(50) + Mod12(2).isBig == Mod12(50).isBig + Mod12(2) == Mod12(110) + Mod12(2).isBig == Mod12(110).isBig + Mod12(2).isBig + Mod12(110).isBig +} + +Mod12(1) == Mod12(6) +Mod12(1) == Mod12(13) +Mod12(1) == Mod12(25) + +struct NeverEqual: Equatable { + var value: A + init(_ value: A) { + self.value = value + } + static func == (lhs: Self, rhs: Self) -> Bool { false } +} + +do { + let neverEqual1 = NeverEqual(1) + neverEqual1 == neverEqual1 + + let values = [NeverEqual(true), NeverEqual(false)] + values.count + values.contains(NeverEqual(true)) + values.contains(NeverEqual(false)) +} + +struct LessThanOrEqual: Equatable { + var value: Int + init(_ value: Int) { + self.value = value + } + static func == (lhs: Self, rhs: Self) -> Bool { + lhs.value <= rhs.value + } +} + +LessThanOrEqual(2) == LessThanOrEqual(3) +LessThanOrEqual(3) == LessThanOrEqual(2) + +extension Array where Element: Equatable { + func firstOffset(of needle: Element) -> Int? { + for (offset, element) in enumerated() { + if needle == element { +// if element == needle { + return offset + } + } + return nil + } +} + +[ + LessThanOrEqual(2), + LessThanOrEqual(3), +] + .firstOffset(of: LessThanOrEqual(3)) + +struct Approximation: Equatable { + var value: Double + init(_ value: Double) { + self.value = value + } + static func == (lhs: Self, rhs: Self) -> Bool { + abs(lhs.value - rhs.value) < 0.1 + } +} + +Approximation(1) == Approximation(1.05) +Approximation(1.05) == Approximation(1.1) +Approximation(1) == Approximation(1.1) + +extension Array where Element: Equatable { + func uniques() -> Array { + var result = Array() + for element in self { + if !result.contains(element) { + result.append(element) + } + } + return result + } +} + +[ + Approximation(1), + Approximation(1.05), + Approximation(1.025), + Approximation(1.075), + Approximation(1.1), + Approximation(1.15), +] + .uniques() + .map(\.value) + +func f(_ a: A) -> Bool { + // + fatalError() +} +do { +// let x: Int +// let y: Int +// if x == y { +// f(x) == f(y) +// } +} +func algorithm(lhs: A, rhs: A) -> Bool { + if lhs == rhs { + // fast path using 'lhs' + } else { + // slow path using both 'lhs' and 'rhs' + } + fatalError() +} diff --git a/0297-back-to-basics-equatable-pt1/BackToBasicsEquatable/BackToBasicsEquatable.playground/contents.xcplayground b/0297-back-to-basics-equatable-pt1/BackToBasicsEquatable/BackToBasicsEquatable.playground/contents.xcplayground new file mode 100644 index 00000000..e8c513a4 --- /dev/null +++ b/0297-back-to-basics-equatable-pt1/BackToBasicsEquatable/BackToBasicsEquatable.playground/contents.xcplayground @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/0297-back-to-basics-equatable-pt1/BackToBasicsEquatable/BackToBasicsEquatable.xcodeproj/project.pbxproj b/0297-back-to-basics-equatable-pt1/BackToBasicsEquatable/BackToBasicsEquatable.xcodeproj/project.pbxproj new file mode 100644 index 00000000..f866aaf8 --- /dev/null +++ b/0297-back-to-basics-equatable-pt1/BackToBasicsEquatable/BackToBasicsEquatable.xcodeproj/project.pbxproj @@ -0,0 +1,292 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 77; + objects = { + +/* Begin PBXCopyFilesBuildPhase section */ + 4B7FD74B2CAB1B8100205C7D /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 4B7FD74D2CAB1B8100205C7D /* BackToBasicsEquatable */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = BackToBasicsEquatable; sourceTree = BUILT_PRODUCTS_DIR; }; + 4B7FD7572CAB1B9000205C7D /* BackToBasicsEquatable.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = BackToBasicsEquatable.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; +/* End PBXFileReference section */ + +/* Begin PBXFileSystemSynchronizedRootGroup section */ + 4B7FD74F2CAB1B8100205C7D /* BackToBasicsEquatable */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = BackToBasicsEquatable; + sourceTree = ""; + }; +/* End PBXFileSystemSynchronizedRootGroup section */ + +/* Begin PBXFrameworksBuildPhase section */ + 4B7FD74A2CAB1B8100205C7D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 4B7FD7442CAB1B8100205C7D = { + isa = PBXGroup; + children = ( + 4B7FD7572CAB1B9000205C7D /* BackToBasicsEquatable.playground */, + 4B7FD74F2CAB1B8100205C7D /* BackToBasicsEquatable */, + 4B7FD74E2CAB1B8100205C7D /* Products */, + ); + sourceTree = ""; + }; + 4B7FD74E2CAB1B8100205C7D /* Products */ = { + isa = PBXGroup; + children = ( + 4B7FD74D2CAB1B8100205C7D /* BackToBasicsEquatable */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 4B7FD74C2CAB1B8100205C7D /* BackToBasicsEquatable */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4B7FD7542CAB1B8100205C7D /* Build configuration list for PBXNativeTarget "BackToBasicsEquatable" */; + buildPhases = ( + 4B7FD7492CAB1B8100205C7D /* Sources */, + 4B7FD74A2CAB1B8100205C7D /* Frameworks */, + 4B7FD74B2CAB1B8100205C7D /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + 4B7FD74F2CAB1B8100205C7D /* BackToBasicsEquatable */, + ); + name = BackToBasicsEquatable; + packageProductDependencies = ( + ); + productName = BackToBasicsEquatable; + productReference = 4B7FD74D2CAB1B8100205C7D /* BackToBasicsEquatable */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 4B7FD7452CAB1B8100205C7D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1600; + LastUpgradeCheck = 1600; + TargetAttributes = { + 4B7FD74C2CAB1B8100205C7D = { + CreatedOnToolsVersion = 16.0; + }; + }; + }; + buildConfigurationList = 4B7FD7482CAB1B8100205C7D /* Build configuration list for PBXProject "BackToBasicsEquatable" */; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 4B7FD7442CAB1B8100205C7D; + minimizedProjectReferenceProxies = 1; + preferredProjectObjectVersion = 77; + productRefGroup = 4B7FD74E2CAB1B8100205C7D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 4B7FD74C2CAB1B8100205C7D /* BackToBasicsEquatable */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 4B7FD7492CAB1B8100205C7D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 4B7FD7522CAB1B8100205C7D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 4B7FD7532CAB1B8100205C7D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + }; + name = Release; + }; + 4B7FD7552CAB1B8100205C7D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 4B7FD7562CAB1B8100205C7D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 4B7FD7482CAB1B8100205C7D /* Build configuration list for PBXProject "BackToBasicsEquatable" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4B7FD7522CAB1B8100205C7D /* Debug */, + 4B7FD7532CAB1B8100205C7D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4B7FD7542CAB1B8100205C7D /* Build configuration list for PBXNativeTarget "BackToBasicsEquatable" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4B7FD7552CAB1B8100205C7D /* Debug */, + 4B7FD7562CAB1B8100205C7D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 4B7FD7452CAB1B8100205C7D /* Project object */; +} diff --git a/0297-back-to-basics-equatable-pt1/BackToBasicsEquatable/BackToBasicsEquatable.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/0297-back-to-basics-equatable-pt1/BackToBasicsEquatable/BackToBasicsEquatable.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/0297-back-to-basics-equatable-pt1/BackToBasicsEquatable/BackToBasicsEquatable.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/0297-back-to-basics-equatable-pt1/BackToBasicsEquatable/BackToBasicsEquatable/main.swift b/0297-back-to-basics-equatable-pt1/BackToBasicsEquatable/BackToBasicsEquatable/main.swift new file mode 100644 index 00000000..c3998546 --- /dev/null +++ b/0297-back-to-basics-equatable-pt1/BackToBasicsEquatable/BackToBasicsEquatable/main.swift @@ -0,0 +1,11 @@ +// +// main.swift +// BackToBasicsEquatable +// +// Created by Point-Free on 9/30/24. +// + +import Foundation + +print("Hello, World!") + diff --git a/0297-back-to-basics-equatable-pt1/README.md b/0297-back-to-basics-equatable-pt1/README.md new file mode 100644 index 00000000..0e3d3295 --- /dev/null +++ b/0297-back-to-basics-equatable-pt1/README.md @@ -0,0 +1,5 @@ +## [Point-Free](https://www.pointfree.co) + +> #### This directory contains code from Point-Free Episode: [Back to Basics: Equatable](https://www.pointfree.co/episodes/ep297-back-to-basics-equatable) +> +> In this series we go back to basics with a deep dive into the subject of `Equatable` types. Equatability is a deceptively simple topic. It is a surprisingly tricky protocol that has some very specific semantics that must be upheld baked into it, and there are many misconceptions on how one can or should conform types to this protocol. diff --git a/0298-back-to-basics-equatable-pt2/BackToBasicsEquatable/BackToBasicsEquatable.playground/Contents.swift b/0298-back-to-basics-equatable-pt2/BackToBasicsEquatable/BackToBasicsEquatable.playground/Contents.swift new file mode 100644 index 00000000..e0bd283c --- /dev/null +++ b/0298-back-to-basics-equatable-pt2/BackToBasicsEquatable/BackToBasicsEquatable.playground/Contents.swift @@ -0,0 +1,341 @@ +//let x: any Equatable + +struct User: Equatable, Hashable { + let id: Int + var isAdmin = false + var name: String + + static func == (lhs: Self, rhs: Self) -> Bool { + return lhs.id == rhs.id +// && lhs.isAdmin == rhs.isAdmin +// && lhs.name == rhs.name +// lhs.id == rhs.id +// lhs.isAdmin == rhs.isAdmin && lhs.name == rhs.name + } + + func hash(into hasher: inout Hasher) { + hasher.combine(id) + hasher.combine(isAdmin) + hasher.combine(name) + } +} + +struct SlowDictionary { + let keyValues: [(Key, Value)] + + subscript(key: Key) -> Value? where Key: Equatable { + for (k, v) in keyValues { + if key == k { + return v + } + } + return nil + } +} + +do { + let blob = User(id: 42, isAdmin: false, name: "Blob") + var friends: [User: [User]] = [:] + + friends[blob] = [ + User(id: 43, name: "Blob Jr."), + User(id: 44, name: "Blob Sr."), + ] + + friends[blob] + blob.hashValue + let blobJr = User(id: 43, name: "Blob Jr.") + friends[blobJr] + + blob.hashValue + blobJr.hashValue + + let users = Set([ + blob, + blob, + blob, + blob, + blobJr, + blobJr, + blobJr, + ]) + users.contains(blob) + users.contains(User(id: 44, name: "Blob Sr.")) + + var blobDraft = blob + blobDraft.isAdmin.toggle() + blob == blobDraft + blob.hashValue == blobDraft.hashValue + friends[blob] + friends[blobDraft] + +// friends[blobDraft] = [] + + var friendsSlow = SlowDictionary( + keyValues: [ + (blob, [ + User(id: 43, name: "Blob Jr."), + User(id: 44, name: "Blob Sr."), + ]) + ] + ) + + friendsSlow[blob] + friendsSlow[blobDraft] +} + +let id42Partition = [ + User(id: 42, isAdmin: true, name: "Blob"), + User(id: 42, isAdmin: false, name: "Blob, Esq."), + User(id: 42, isAdmin: true, name: "Blob, Esq."), + User(id: 42, isAdmin: true, name: "Blob, MD"), + User(id: 42, isAdmin: true, name: "Blob, MD"), + // ... +] + +id42Partition.allSatisfy { lhs in + id42Partition.allSatisfy { rhs in + lhs == rhs + } +} + +struct Mod12: Equatable { + var value: Int + init(_ value: Int) { + self.value = value + } + + static func == (lhs: Self, rhs: Self) -> Bool { + (rhs.value - lhs.value).isMultiple(of: 12) + } + + func add(to other: Self) -> Self { + Self(value + other.value) + } + var isBig: Bool { + value >= 100 + } +} +func algorithm(lhs: Mod12, rhs: Mod12) { + let bothAreBig = lhs == rhs + ? lhs.isBig + : lhs.isBig && rhs.isBig +} + +do { + let three = Mod12(3) + let fifteen = Mod12(15) + Mod12(2).add(to: three) == Mod12(2).add(to: fifteen) + + Mod12(2) == Mod12(50) + Mod12(2).isBig == Mod12(50).isBig + Mod12(2) == Mod12(110) + Mod12(2).isBig == Mod12(110).isBig + Mod12(2).isBig + Mod12(110).isBig +} + +Mod12(1) == Mod12(6) +Mod12(1) == Mod12(13) +Mod12(1) == Mod12(25) + +struct NeverEqual: Equatable { + var value: A + init(_ value: A) { + self.value = value + } + static func == (lhs: Self, rhs: Self) -> Bool { false } +} + +do { + let neverEqual1 = NeverEqual(1) + neverEqual1 == neverEqual1 + + let values = [NeverEqual(true), NeverEqual(false)] + values.count + values.contains(NeverEqual(true)) + values.contains(NeverEqual(false)) +} + +struct LessThanOrEqual: Equatable { + var value: Int + init(_ value: Int) { + self.value = value + } + static func == (lhs: Self, rhs: Self) -> Bool { + lhs.value <= rhs.value + } +} + +LessThanOrEqual(2) == LessThanOrEqual(3) +LessThanOrEqual(3) == LessThanOrEqual(2) + +extension Array where Element: Equatable { + func firstOffset(of needle: Element) -> Int? { + for (offset, element) in enumerated() { + if needle == element { +// if element == needle { + return offset + } + } + return nil + } +} + +[ + LessThanOrEqual(2), + LessThanOrEqual(3), +] + .firstOffset(of: LessThanOrEqual(3)) + +struct Approximation: Equatable { + var value: Double + init(_ value: Double) { + self.value = value + } + static func == (lhs: Self, rhs: Self) -> Bool { + abs(lhs.value - rhs.value) < 0.1 + } +} + +Approximation(1) == Approximation(1.05) +Approximation(1.05) == Approximation(1.1) +Approximation(1) == Approximation(1.1) + +extension Array where Element: Equatable { + func uniques() -> Array { + var result = Array() + for element in self { + if !result.contains(element) { + result.append(element) + } + } + return result + } +} + +[ + Approximation(1), + Approximation(1.05), + Approximation(1.025), + Approximation(1.075), + Approximation(1.1), + Approximation(1.15), +] + .uniques() + .map(\.value) + +func f(_ a: A) -> Bool { + // + fatalError() +} +do { +// let x: Int +// let y: Int +// if x == y { +// f(x) == f(y) +// } +} +func algorithm(lhs: A, rhs: A) -> Bool { + if lhs == rhs { + // fast path using 'lhs' + } else { + // slow path using both 'lhs' and 'rhs' + } + fatalError() +} + +Double.nan + +Double.zero / .zero + +import Foundation + +sqrt(-1) +Double.infinity * .zero + +let nanValue = Double.nan +nanValue == nanValue + +let veryLargeNumber: Double = 1_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000 +veryLargeNumber == veryLargeNumber + 1 + +Double.zero +-Double.zero + +Double.zero == -.zero + +func isSpecialNumber(_ value: Double) -> Bool { + 1 / value == .infinity +} + +isSpecialNumber(.zero) +isSpecialNumber(-.zero) + +do { + let name = "Blob" + + let cafe = "Café" + + name == name + cafe == name + name == cafe + + let cafe1 = "Caf\u{e9}" + let cafe2 = "Cafe\u{301}" + cafe1 == cafe2 + + struct Flag: Equatable { + let id: UUID + var isEnabled = false + } + + let dejavu = "déjà-vu" + let dejavu1 = "d\u{e9}j\u{e0}-vu" + let dejavu2 = "de\u{301}j\u{e0}-vu" + let dejavu3 = "d\u{e9}ja\u{300}-vu" + let dejavu4 = "de\u{301}ja\u{300}-vu" + + dejavu1 == dejavu2 + dejavu2 == dejavu3 + dejavu3 == dejavu4 + dejavu4 == dejavu1 + + dejavu1.hashValue + dejavu2.hashValue + dejavu3.hashValue + dejavu4.hashValue + + Array(cafe1.unicodeScalars).description + Array(cafe2.unicodeScalars).description + cafe1.unicodeScalars.elementsEqual(cafe2.unicodeScalars) + + Array(cafe1.utf8).description + Array(cafe2.utf8).description + cafe1.utf8.elementsEqual(cafe2.utf8) + + func specialAlgorithm(_ str: String) -> Bool { + if str.utf8.count <= 5 { + // Fast path + return true + } else { + // Slow path + return false + } + } + + specialAlgorithm(cafe1) + specialAlgorithm(cafe2) + cafe1 == cafe2 +} + +do { +// let x: Hashable +// let y: Hashable +// if x == y { +// x.hashValue == y.hashValue +// } +// if x.hashValue == y.hashValue { +// x == y +// } +} diff --git a/0298-back-to-basics-equatable-pt2/BackToBasicsEquatable/BackToBasicsEquatable.playground/contents.xcplayground b/0298-back-to-basics-equatable-pt2/BackToBasicsEquatable/BackToBasicsEquatable.playground/contents.xcplayground new file mode 100644 index 00000000..e8c513a4 --- /dev/null +++ b/0298-back-to-basics-equatable-pt2/BackToBasicsEquatable/BackToBasicsEquatable.playground/contents.xcplayground @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/0298-back-to-basics-equatable-pt2/BackToBasicsEquatable/BackToBasicsEquatable.xcodeproj/project.pbxproj b/0298-back-to-basics-equatable-pt2/BackToBasicsEquatable/BackToBasicsEquatable.xcodeproj/project.pbxproj new file mode 100644 index 00000000..f866aaf8 --- /dev/null +++ b/0298-back-to-basics-equatable-pt2/BackToBasicsEquatable/BackToBasicsEquatable.xcodeproj/project.pbxproj @@ -0,0 +1,292 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 77; + objects = { + +/* Begin PBXCopyFilesBuildPhase section */ + 4B7FD74B2CAB1B8100205C7D /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 4B7FD74D2CAB1B8100205C7D /* BackToBasicsEquatable */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = BackToBasicsEquatable; sourceTree = BUILT_PRODUCTS_DIR; }; + 4B7FD7572CAB1B9000205C7D /* BackToBasicsEquatable.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = BackToBasicsEquatable.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; +/* End PBXFileReference section */ + +/* Begin PBXFileSystemSynchronizedRootGroup section */ + 4B7FD74F2CAB1B8100205C7D /* BackToBasicsEquatable */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = BackToBasicsEquatable; + sourceTree = ""; + }; +/* End PBXFileSystemSynchronizedRootGroup section */ + +/* Begin PBXFrameworksBuildPhase section */ + 4B7FD74A2CAB1B8100205C7D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 4B7FD7442CAB1B8100205C7D = { + isa = PBXGroup; + children = ( + 4B7FD7572CAB1B9000205C7D /* BackToBasicsEquatable.playground */, + 4B7FD74F2CAB1B8100205C7D /* BackToBasicsEquatable */, + 4B7FD74E2CAB1B8100205C7D /* Products */, + ); + sourceTree = ""; + }; + 4B7FD74E2CAB1B8100205C7D /* Products */ = { + isa = PBXGroup; + children = ( + 4B7FD74D2CAB1B8100205C7D /* BackToBasicsEquatable */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 4B7FD74C2CAB1B8100205C7D /* BackToBasicsEquatable */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4B7FD7542CAB1B8100205C7D /* Build configuration list for PBXNativeTarget "BackToBasicsEquatable" */; + buildPhases = ( + 4B7FD7492CAB1B8100205C7D /* Sources */, + 4B7FD74A2CAB1B8100205C7D /* Frameworks */, + 4B7FD74B2CAB1B8100205C7D /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + 4B7FD74F2CAB1B8100205C7D /* BackToBasicsEquatable */, + ); + name = BackToBasicsEquatable; + packageProductDependencies = ( + ); + productName = BackToBasicsEquatable; + productReference = 4B7FD74D2CAB1B8100205C7D /* BackToBasicsEquatable */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 4B7FD7452CAB1B8100205C7D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1600; + LastUpgradeCheck = 1600; + TargetAttributes = { + 4B7FD74C2CAB1B8100205C7D = { + CreatedOnToolsVersion = 16.0; + }; + }; + }; + buildConfigurationList = 4B7FD7482CAB1B8100205C7D /* Build configuration list for PBXProject "BackToBasicsEquatable" */; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 4B7FD7442CAB1B8100205C7D; + minimizedProjectReferenceProxies = 1; + preferredProjectObjectVersion = 77; + productRefGroup = 4B7FD74E2CAB1B8100205C7D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 4B7FD74C2CAB1B8100205C7D /* BackToBasicsEquatable */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 4B7FD7492CAB1B8100205C7D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 4B7FD7522CAB1B8100205C7D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 4B7FD7532CAB1B8100205C7D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + }; + name = Release; + }; + 4B7FD7552CAB1B8100205C7D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 4B7FD7562CAB1B8100205C7D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 4B7FD7482CAB1B8100205C7D /* Build configuration list for PBXProject "BackToBasicsEquatable" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4B7FD7522CAB1B8100205C7D /* Debug */, + 4B7FD7532CAB1B8100205C7D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4B7FD7542CAB1B8100205C7D /* Build configuration list for PBXNativeTarget "BackToBasicsEquatable" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4B7FD7552CAB1B8100205C7D /* Debug */, + 4B7FD7562CAB1B8100205C7D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 4B7FD7452CAB1B8100205C7D /* Project object */; +} diff --git a/0298-back-to-basics-equatable-pt2/BackToBasicsEquatable/BackToBasicsEquatable.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/0298-back-to-basics-equatable-pt2/BackToBasicsEquatable/BackToBasicsEquatable.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/0298-back-to-basics-equatable-pt2/BackToBasicsEquatable/BackToBasicsEquatable.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/0298-back-to-basics-equatable-pt2/BackToBasicsEquatable/BackToBasicsEquatable/main.swift b/0298-back-to-basics-equatable-pt2/BackToBasicsEquatable/BackToBasicsEquatable/main.swift new file mode 100644 index 00000000..c3998546 --- /dev/null +++ b/0298-back-to-basics-equatable-pt2/BackToBasicsEquatable/BackToBasicsEquatable/main.swift @@ -0,0 +1,11 @@ +// +// main.swift +// BackToBasicsEquatable +// +// Created by Point-Free on 9/30/24. +// + +import Foundation + +print("Hello, World!") + diff --git a/0298-back-to-basics-equatable-pt2/README.md b/0298-back-to-basics-equatable-pt2/README.md new file mode 100644 index 00000000..0721bb67 --- /dev/null +++ b/0298-back-to-basics-equatable-pt2/README.md @@ -0,0 +1,5 @@ +## [Point-Free](https://www.pointfree.co) + +> #### This directory contains code from Point-Free Episode: [Back to Basics: Hashable](https://www.pointfree.co/episodes/ep298-back-to-basics-hashable) +> +> While the documentation for `Equatable` discusses the notions of “equivalence relation” _and_ “substitutability”, there are conformances in the Standard Library that run afoul, but for pragmatic reasons. Let’s explore them and then dive deeper into a related protocol: `Hashable`. diff --git a/README.md b/README.md index 2636b24e..e61b22ab 100644 --- a/README.md +++ b/README.md @@ -296,3 +296,7 @@ This repository is the home of code written on episodes of [Point-Free](https:// 1. [Cross-Platform Swift: Networking](0292-cross-platform-pt3) 1. [Cross-Platform Swift: Navigation](0293-cross-platform-pt4) 1. [Cross-Platform Swift: UI Controls](0294-cross-platform-pt5) +1. [Cross-Platform Swift: New Features](0295-cross-platform-pt6) +1. [Cross-Platform Swift: Persistence](0296-cross-platform-pt7) +1. [Back to Basics: Equatable](0297-back-to-basics-equatable-pt1) +1. [Back to Basics: Hashable](0298-back-to-basics-equatable-pt2)