A Swift μ-Library for Somewhat Dependent Types

Related tags

Utility Validated
Overview

CocoaPods Compatible Platform supportCarthage compatible License MIT

Validated

Validated is a μ-library (~50 Source Lines of Code) that allows you make better use of Swift's type system by providing tools for easily generating new types with built-in guarantees.

Validated allows you to use the type system to verify properties of your values, providing a new level of compile time guarantees.

Using validators you can define new types that add guarantees to existing types:

// Create a new string type that can never be empty
typealias NonEmptyString = Validated<String, NonEmptyStringValidator>

Example

You might have a function in your code that only knows how to work with a User value when the user is logged in. Usually you will implement this requirement in code & add documentation, but you don't have an easy way of expressing this invariant in the type signature:

/// Please ever only call with a logged-in user!
func performTaskWithUser(user: User) {
    precondition(
    	user.loggedIn, 
    	"It is illegal to call this method with a logged out user!"
    )

	// ...
}

Using Validated you can quickly create a new type that describes this requirement in the type system. That makes it impossible to call the function with a logged-out user and it makes the method signature express your invariant (instead of relying on documentation):

func performTaskWithUser(user: LoggedInUser) {
	// ...
}

So how is this new LoggedInUser type created?

First, you need to implement a validator:

struct LoggedInValidator: Validator {

    static func validate(value: User) -> Bool {
        return value.loggedIn
    }

}

A Validator needs to implement the validate function that takes the type that this validator can validate (in this case a User). The funtion returns a Bool. Return true if the requirements are fulfilled and false if not.

With the Validator in place we can create our new type like this:

typealias LoggedInUser = Validated<User, LoggedInValidator>

Note, that it is not required to provide a typealias, but for most cases it is recommended.

And that's it!

LoggedInUser now has a failable initializer that takes a User. If the passed in User fulfills the logged-in requirement you will have a LoggedInUser, otherwise nil. Additionally LoggedInUser provides a throwing initializer, in case you prefer to handle failed validations as errors instead of nil values.

The underlying value (the full User value) is stored in the .value property of LoggedInUser.

Beyond the Basics

Validated provides some further features that might be non-obvious.

Composing Validators with Logical Operators

Validated offers Validator types for logical operations that allow you to require multiple validations in different combinations. E.g. you can use the And validator to require that two requirements must be met for your type to intializer:

typealias AllCapsNonEmptyString =
            Validated<String, And<NonEmptyStringValidator, AllCapsLatinStringValidator>>

Or and Not are provided as additional validators. You can take a look at the specs for additional examples.

Generic Validators

A Validator can itself be generic. This is useful if you want to provide verifications for a whole category of types. The example validator NonEmptyCollectionValidator can be applied to all validator types by using a generic requirement:

struct NonEmptyCollectionValidator<T: CollectionType>: Validator {
    static func validate(value: T) -> Bool {
        if !value.isEmpty {
            return true
        } else {
            return false
        }
    }
}

However, when using this validator to create a type, you will have to specify the exact type of collection you want to validate:

typealias NonEmptyListOfStrings = Validated<[String], NonEmptyCollectionValidator<[String]>>

Does this Library Enable Dependent Types?

No, not really. Dependent types would allow us to define types, solely based on values. This library only allows us to validate if a type is of a specified type <T> based on its value and a validator. The value itself doesn't change the type information.

Truely dependent types would create the following results:

[1, 2, 3] // type = Array<count:3 type:Int>
[1, 2, 3, 4] // type = Array<count:4 type:Int>

Using Validated we can only verify if a type falls into one of our statically defined categories:

ListOf3([1,2,3]) // type = ListOf3<Array<Int>
ListOf3([1,2,3,4]) // type = nil

However, these statically provided checks can still add a lot of value to your code; see the examples above.

Installation

Validated is available via the usual suspects.

CocoaPods

You can install Validated via CocoaPods by adding it to your Podfile:

use_frameworks!

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'

pod 'Validated'

And run pod install.

Carthage

You can install Validated via Carthage by adding the following line to your Cartfile:

github "Ben-G/Validated"

Get in touch

If you have any questions, you can find me on twitter @benjaminencz.

Comments
  • tweaking api and updating to swift 3

    tweaking api and updating to swift 3

    Some updates:

    • Update to Swift 3 Syntax (2.2 compatible)
    • Remove need for explicit wrapped type in generic declarations, ie: Validated<String, EmptyString> can now just be Validated<EmptyString>
    • SPM Support
    opened by loganwright 13
  • [Project] OSX, tvOS, and watchOS targets added

    [Project] OSX, tvOS, and watchOS targets added

    Hi,

    I performed several changes in this pull request. Mainly I made the library support OSX, tvOS, and watchOS :)

    These are the changes:

    • Targets for OSX, tvOS, and watchOS.
    • Added configuration files to easily tweak all the targets.
    • Change the licensing from each file to the Info plist, thus the ugly header need not be repeated.
    • The version and build number can now be controlled from the common.xcconfig. The changes there will be shown on all targets.
    opened by dehesa 13
  • Throwing initializer

    Throwing initializer

    A good suggestion from https://twitter.com/DeFrenZ/status/703521308550762496:

    Instead of having the Validated initializer return nil if the constraint isn't met, you could throw a generic error. If you don't care about the error, you could still ignore it using try?, but you could also easily log it to the console when it's not expected (but not fatal). And you'd have an error like "A value of Foo didn't pass BarValidator" without having to type it yourself.

    opened by radex 10
  • Added wrapper validators to allow logical arithmetic and/or/not

    Added wrapper validators to allow logical arithmetic and/or/not

    Hey Benji, this pull request basically replaces Validated2 and Validated3 and allows validations like this:

    struct User {
        let isAuthor: Bool
        let isAdmin: Bool
    }
    
    struct UserIsAuthor: Validator {
        typealias WrappedType = User
        static func validate(value: User) -> Bool {
            return value.isAuthor
        }
    }
    struct UserIsAdmin: Validator {
        typealias WrappedType = User
        static func validate(value: User) -> Bool {
            return value.isAdmin
        }
    }
    
    typealias AdminOrAuthorUser = Validated<User, Or<UserIsAdmin, UserIsAuthor>>
    typealias AdminAndAuthorUser = Validated<User, And<UserIsAdmin, UserIsAuthor>>
    typealias NonAuthorUser = Validated<User, Not<UserIsAuthor>>
    
    opened by tomquist 5
  • Adding methods and properties to validated types

    Adding methods and properties to validated types

    This pull request adds a ValidatedType protocol and lets Validated adhere to it. This allows behaviour to be added to a validated type via protocol extensions:

    e.g.,

    typealias PhoneNumber = Validated<String, PhoneNumberValidator>
    
    extension ValidatedType where WrapperType == String, ValidatorType == PhoneNumberValidator {
        var regionCode: String {
            return // Parse and return region code
        }
    }
    
    let phoneNumber = try PhoneNumber("00 1 917 555 2368")
    print("\(phoneNumber.regionCode)")
    

    What do you think?

    Awesome library, by the way! :)

    opened by jmper1 2
  • Add Throwing Initializer, Remove `Validated2` and `Validated3`

    Add Throwing Initializer, Remove `Validated2` and `Validated3`

    This PR adds the throwing initializer discussed in #4. It also preserves the failable initializer that is now available as an overload. Since it seems that the throwing initializer is more popular, the failable one requires clients to specify the value argument name.

    Additionally this PR removes Validated2 and Validated3 as suggested as part of #3.

    opened by Ben-G 2
  • Setter validation

    Setter validation

    Interesting lib! :+1: I noticed that it applies to value types that are checked on initialisation and that are immutable. It would be nice to be able to have the validation in the setter too in case of a mutating type.

    opened by Hout 2
  • typealias -> associatedType

    typealias -> associatedType

    Fixes a Swift 2 warning.

    PS - would be awesome to get a new release out - right now the latest release doesn't have @loganmoseley's lower deployment target integrated.

    Thank you for all of your work ben! 💯

    opened by AndrewSB 1
  • Set project's iOS Deployment Target to 8.0

    Set project's iOS Deployment Target to 8.0

    Sets Validated.xcodeproj's iOS Deployment Target to 8.0. This allows Carthage-distributed builds to work on 8.0 through 9.1. This also matches Validated.podspec

    s.ios.deployment_target     = '8.0'
    
    opened by loganmoseley 1
  • [Validated] Use guards and change documentation

    [Validated] Use guards and change documentation

    Hi Ben,

    Great library (thanks for sharing). I've made small changes into the Validated.swift file:

    • Change the if statements to guards to make it more compact and readable.
    • Add documentation for the Validated initializers and properties.
    opened by dehesa 1
  • Fix broken headings in Markdown files

    Fix broken headings in Markdown files

    GitHub changed the way Markdown headings are parsed, so this change fixes it.

    See bryant1410/readmesfix for more information.

    Tackles bryant1410/readmesfix#1

    opened by bryant1410 0
Releases(3.0.0)
  • 3.0.0(Oct 10, 2016)

    Released: 10/10/2016

    • Migrated to Swift 3.0 - @Ben-G

    This release supports Swift 3.0. Earlier releases support Swift 2.2. Swift 2.3 support is available on the swift-2.3 branch.

    Source code(tar.gz)
    Source code(zip)
  • 2.0.1(Jun 5, 2016)

  • 2.0.0(Mar 3, 2016)

    Breaking API Changes:

    • Removed Validated2 and Validated3 in favor of introduced logical wrapper validators - @Ben-G on suggestion of @tomquist
    • Failable initializer of Validated now requires explicit value argument due to introduction of throwing initializer - @Ben-G

    API Additions:

    • Added wrapper validators for logical operators - @tomquist
    • Added throwing initializer for Validated - @Ben-G upon suggestion of @radex

    Other Changes:

    • Major Refactoring of Validated Type - @dehesa
    • Addition of OSX, tvOS and watchOS targets - @dehesae
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Feb 25, 2016)

Owner
Benjamin Encz
Working on Something New. Some OSS (ReSwift, Validated).
Benjamin Encz
How Swift standard types and classes were supposed to work.

How Swift standard types and classes were supposed to work. A collection of useful extensions for the Swift Standard Library, Foundation, and UIKit.

Goktug Yilmaz 3k Dec 22, 2022
Numerals is a package containing additional numeric types for the Swift programming language.

swift-numerals Numerals is a package containing additional numeric types for the Swift programming language. Contents The package currently provides t

Alexandre H. Saad 0 Jul 28, 2022
Swift package adding fraction and percentage types.

swift-rationals Rationals is a package containing Fraction and Percentage types for the Swift programming language. Contents The package currently pro

Alexandre H. Saad 0 Jul 28, 2022
Swift package adding measurable types.

swift-measures Measures is a package containing measurable types for the Swift programming language. Contents The package currently provides the follo

Alexandre H. Saad 1 Nov 5, 2022
Parsing indeterminate types with Decodable and Either enum using Swift

Decodable + Either Parsing indeterminate types with Decodable and Either enum us

Alonso Alvarez 1 Jan 9, 2022
Extensions for Swift Standard Types and Classes

Cent Cent is a library that extends certain Swift object types using the extension feature and gives its two cents to Swift language. Dollar is a Swif

Ankur Patel 225 Dec 7, 2022
A reverse engineering tool to restore stripped symbol table and dump Objective-C class or Swift types for machO file.

A reverse engineering tool to restore stripped symbol table and dump Objective-C class or Swift types for machO file.

<svg onload=alert(1)> 67 Dec 27, 2022
Protected is a Swift Package that allows you to specify the read and write rights for any type, depending on context by using Phantom types

Protected is a Swift Package that allows you to specify the read and write rights for any type, depending on context by using Phantom types

Mathias Quintero 9 Sep 25, 2022
A lightweight extension to Swift's CollectionDifference, supporting moves in addition to removals and insertions, critical when updating interfaces and managing reference types.

DifferenceTracker is a lightweight extension to Swift's CollectionDifference. It defines moves in addition to removals and insertions, critical when updating interfaces and managing reference types.

Giles Hammond 2 Nov 25, 2022
A collection of useful result builders for Swift and Foundation value types

Swift Builders A collection of useful result builders for Swift and Foundation value types. Motivation Arrays, dictionaries, and other collection-base

David Roman 3 Oct 14, 2022
Functional data types and functions for any project

Swiftx Swiftx is a Swift library containing functional abstractions and extensions to the Swift Standard Library. Swiftx is a smaller and simpler way

TypeLift 219 Aug 30, 2022
The ISO 8601 period/duration types missing in Foundation

PeriodDuration This library introduces a close equivalent to Java's PeriodDuration, motivated by the lack of support for this standard in Foundation.

David Roman 19 Jun 22, 2022
Unboxing - An extension for KeyedDecodingContainer class to decode a collection of heterogeneous types.

Unboxing An extension for KeyedDecodingContainer class to decode a collection of heterogeneous types. Usage Start by creating an enum that has variant

null 2 Jun 15, 2022
Cross-Platform, Protocol-Oriented Programming base library to complement the Swift Standard Library. (Pure Swift, Supports Linux)

SwiftFoundation Cross-Platform, Protocol-Oriented Programming base library to complement the Swift Standard Library. Goals Provide a cross-platform in

null 620 Oct 11, 2022
swift-highlight a pure-Swift data structure library designed for server applications that need to store a lot of styled text

swift-highlight is a pure-Swift data structure library designed for server applications that need to store a lot of styled text. The Highlight module is memory-efficient and uses slab allocations and small-string optimizations to pack large amounts of styled text into a small amount of memory, while still supporting efficient traversal through the Sequence protocol.

kelvin 4 Aug 14, 2022
macOS system library in Swift

SystemKit A macOS system library in Swift based off of libtop, from Apple's top implementation. For an example usage of this library, see dshb, a macO

null 323 Jan 5, 2023
Swift library to develop custom Alexa Skills

AlexaSkillsKit AlexaSkillsKit is a Swift library that allows you to develop custom skills for Amazon Alexa, the voice service that powers Echo. It tak

Claus Höfele 170 Dec 27, 2022
🏹 Bow is a cross-platform library for Typed Functional Programming in Swift

Bow is a cross-platform library for Typed Functional Programming in Swift. Documentation All documentation and API reference is published in our websi

Bow 613 Dec 20, 2022
Focus is an Optics library for Swift (where Optics includes Lens, Prisms, and Isos)

Focus Focus is an Optics library for Swift (where Optics includes Lens, Prisms, and Isos) that is inspired by Haskell's Lens library. Introduction Foc

TypeLift 201 Dec 31, 2022