Type Safe Algorithms


(James Campbell) #1

I implemented a way of type safeing a calculation in Swift. I.e marking an
Int as a Degree and then being able to convert to a Radian. (At the bottom
of the page)

The magic for these special structs was the AngleType protocol which allows
you to Box up a value (in this case a number) and it handles the Conversion
(Apart from two of the methods which I had to implement).

In theory we could abstract this protocol out, so that others could use it
in the library. Then they just use it with their structs and they can
handle converting between these types.

So two questions do we have something like this already? and if not would
this be useful ?

import Foundation

//MARK:- AngleType

protocol AngleType: FloatLiteralConvertible, IntegerLiteralConvertible {

    var value: Double { get set }

    init(_ value: Double)

    init(_ value: Int)

    init<T: IntegerType>(integerLiteral value: T)

    init<T: FloatingPointType>(floatLiteral value: T)

}

// Implement FloatLiteralConvertible and IntegerLiteralConvertible

extension AngleType {

    init<T: IntegerType>(integerLiteral value: T)

    {

        self.init(value)

    }

    init<T: IntegerType>(_ value: T)

    {

        self.init(integerLiteral: value)

    }

    init<T: FloatingPointType>(floatLiteral value: T)

    {

        self.init(value)

    }

    init<T: FloatingPointType>(_ value: T)

    {

        self.init(floatLiteral: value)

    }

}

//MARK:- Degree

struct Degree: AngleType {

    typealias FloatLiteralType = Double

    typealias IntegerLiteralType = Int

    var value: Double

    init(_ value: Double) {

        self.value = value

    }

    init(_ value: Int) {

        self.value = Double(value)

    }

}

protocol DegreeConvertiable {

    init(degreeLiteral value: Degree)

}

extension Degree: CustomStringConvertible, CustomDebugStringConvertible {

    var description: String {

        return self.value.description

    }

    var debugDescription: String {

        return "\(self.value.description)°"

    }

}

extension Degree: RadianConvertiable {

    init(radianLiteral value: Radian) {

        self.value = Double(radianLiteral:value) * 180.0 / M_PI

    }

    init(_ value: Radian) {

        self.init(radianLiteral: value)

    }

}

//MARK:- Radian

struct Radian: AngleType {

    typealias FloatLiteralType = Double

    typealias IntegerLiteralType = Int

    var value: Double

    init(_ value: Double) {

        self.value = value

    }

    init(_ value: Int) {

        self.value = Double(value)

    }

}

protocol RadianConvertiable {

    init(radianLiteral value: Radian)

}

extension Radian: CustomStringConvertible, CustomDebugStringConvertible {

    var description: String {

        return self.value.description

    }

    var debugDescription: String {

        return "\(self.value.description)㎭"

    }

}

extension Radian: DegreeConvertiable {

    init(degreeLiteral value: Degree) {

        self.value = Double(degreeLiteral: value) * M_PI / 180.0

    }

    init(_ value: Degree) {

        self.init(degreeLiteral: value)

    }

}

//MARK:- Adding Conformance To Built In Types

extension FloatLiteralType: DegreeConvertiable, RadianConvertiable

{

    init(degreeLiteral degree: Degree) {

        self.value = degree.value.value

    }

    init(radianLiteral radian: Radian) {

        self.value = radian.value.value

    }

}

extension CGFloat: DegreeConvertiable, RadianConvertiable

{

    init(degreeLiteral degree: Degree) {

        self.init(degree.value)

    }

    init(radianLiteral radian: Radian) {

        self.init(radian.value)

    }

    init(_ degree: Degree) {

        self.init(degreeLiteral: degree)

    }

    init(_ radian: Radian) {

        self.init(radianLiteral: radian)

    }

}

···

--
 Wizard
james@supmenow.com
+44 7523 279 698


(Félix Cloutier) #2

There are lots of people who had an idea like this one, the latest just yesterday, where the other threads had been collected: https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160104/005353.html

So there's definitely a lot of interest in that.

Freshly out of engineering school, I really liked how my calculator handled that (a bulky old TI Voyage 200, though I think that the N-Spire line can do it too).

Félix

···

Le 6 janv. 2016 à 10:17:23, James Campbell via swift-evolution <swift-evolution@swift.org> a écrit :

I implemented a way of type safeing a calculation in Swift. I.e marking an Int as a Degree and then being able to convert to a Radian. (At the bottom of the page)

The magic for these special structs was the AngleType protocol which allows you to Box up a value (in this case a number) and it handles the Conversion (Apart from two of the methods which I had to implement).

In theory we could abstract this protocol out, so that others could use it in the library. Then they just use it with their structs and they can handle converting between these types.

So two questions do we have something like this already? and if not would this be useful ?

import Foundation

//MARK:- AngleType

protocol AngleType: FloatLiteralConvertible, IntegerLiteralConvertible {

    var value: Double { get set }

    init(_ value: Double)

    init(_ value: Int)

    init<T: IntegerType>(integerLiteral value: T)

    init<T: FloatingPointType>(floatLiteral value: T)

}

// Implement FloatLiteralConvertible and IntegerLiteralConvertible

extension AngleType {

    init<T: IntegerType>(integerLiteral value: T)

    {

        self.init(value)

    }

    init<T: IntegerType>(_ value: T)

    {

        self.init(integerLiteral: value)

    }

    init<T: FloatingPointType>(floatLiteral value: T)

    {

        self.init(value)

    }

    init<T: FloatingPointType>(_ value: T)

    {

        self.init(floatLiteral: value)

    }

}

//MARK:- Degree

struct Degree: AngleType {

    typealias FloatLiteralType = Double

    typealias IntegerLiteralType = Int

    var value: Double

    init(_ value: Double) {

        self.value = value

    }

    init(_ value: Int) {

        self.value = Double(value)

    }

}

protocol DegreeConvertiable {

    init(degreeLiteral value: Degree)

}

extension Degree: CustomStringConvertible, CustomDebugStringConvertible {

    var description: String {

        return self.value.description

    }

    var debugDescription: String {

        return "\(self.value.description)°"

    }

}

extension Degree: RadianConvertiable {

    init(radianLiteral value: Radian) {

        self.value = Double(radianLiteral:value) * 180.0 / M_PI

    }

    init(_ value: Radian) {

        self.init(radianLiteral: value)

    }

}

//MARK:- Radian

struct Radian: AngleType {

    typealias FloatLiteralType = Double

    typealias IntegerLiteralType = Int

    var value: Double

    init(_ value: Double) {

        self.value = value

    }

    init(_ value: Int) {

        self.value = Double(value)

    }

}

protocol RadianConvertiable {

    init(radianLiteral value: Radian)

}

extension Radian: CustomStringConvertible, CustomDebugStringConvertible {

    var description: String {

        return self.value.description

    }

    var debugDescription: String {

        return "\(self.value.description)㎭"

    }

}

extension Radian: DegreeConvertiable {

    init(degreeLiteral value: Degree) {

        self.value = Double(degreeLiteral: value) * M_PI / 180.0

    }

    init(_ value: Degree) {

        self.init(degreeLiteral: value)

    }

}

//MARK:- Adding Conformance To Built In Types

extension FloatLiteralType: DegreeConvertiable, RadianConvertiable

{

    init(degreeLiteral degree: Degree) {

        self.value = degree.value.value

    }

    init(radianLiteral radian: Radian) {

        self.value = radian.value.value

    }

}

extension CGFloat: DegreeConvertiable, RadianConvertiable

{

    init(degreeLiteral degree: Degree) {

        self.init(degree.value)

    }

    init(radianLiteral radian: Radian) {

        self.init(radian.value)

    }

    init(_ degree: Degree) {

        self.init(degreeLiteral: degree)

    }

    init(_ radian: Radian) {

        self.init(radianLiteral: radian)

    }

}

--
 Wizard
james@supmenow.com <mailto:james@supmenow.com>
+44 7523 279 698
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(James Campbell) #3

Seem like the protocol I implemented is actually a Box, so perhaps just
adding a box type would allow us to do most of these things.

https://github.com/robrix/Box

···

On Wed, Jan 6, 2016 at 4:02 PM, Félix Cloutier <felixcca@yahoo.ca> wrote:

There are lots of people who had an idea like this one, the latest just
yesterday, where the other threads had been collected:
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160104/005353.html

So there's definitely a lot of interest in that.

Freshly out of engineering school, I really liked how my calculator
handled that (a bulky old TI Voyage 200, though I think that the N-Spire
line can do it too).

Félix

Le 6 janv. 2016 à 10:17:23, James Campbell via swift-evolution < > swift-evolution@swift.org> a écrit :

I implemented a way of type safeing a calculation in Swift. I.e marking an
Int as a Degree and then being able to convert to a Radian. (At the bottom
of the page)

The magic for these special structs was the AngleType protocol which
allows you to Box up a value (in this case a number) and it handles the
Conversion (Apart from two of the methods which I had to implement).

In theory we could abstract this protocol out, so that others could use it
in the library. Then they just use it with their structs and they can
handle converting between these types.

So two questions do we have something like this already? and if not would
this be useful ?

import Foundation

//MARK:- AngleType

protocol AngleType: FloatLiteralConvertible, IntegerLiteralConvertible {

    var value: Double { get set }

    init(_ value: Double)

    init(_ value: Int)

    init<T: IntegerType>(integerLiteral value: T)

    init<T: FloatingPointType>(floatLiteral value: T)

}

// Implement FloatLiteralConvertible and IntegerLiteralConvertible

extension AngleType {

    init<T: IntegerType>(integerLiteral value: T)

    {

        self.init(value)

    }

    init<T: IntegerType>(_ value: T)

    {

        self.init(integerLiteral: value)

    }

    init<T: FloatingPointType>(floatLiteral value: T)

    {

        self.init(value)

    }

    init<T: FloatingPointType>(_ value: T)

    {

        self.init(floatLiteral: value)

    }

}

//MARK:- Degree

struct Degree: AngleType {

    typealias FloatLiteralType = Double

    typealias IntegerLiteralType = Int

    var value: Double

    init(_ value: Double) {

        self.value = value

    }

    init(_ value: Int) {

        self.value = Double(value)

    }

}

protocol DegreeConvertiable {

    init(degreeLiteral value: Degree)

}

extension Degree: CustomStringConvertible, CustomDebugStringConvertible {

    var description: String {

        return self.value.description

    }

    var debugDescription: String {

        return "\(self.value.description)°"

    }

}

extension Degree: RadianConvertiable {

    init(radianLiteral value: Radian) {

        self.value = Double(radianLiteral:value) * 180.0 / M_PI

    }

    init(_ value: Radian) {

        self.init(radianLiteral: value)

    }

}

//MARK:- Radian

struct Radian: AngleType {

    typealias FloatLiteralType = Double

    typealias IntegerLiteralType = Int

    var value: Double

    init(_ value: Double) {

        self.value = value

    }

    init(_ value: Int) {

        self.value = Double(value)

    }

}

protocol RadianConvertiable {

    init(radianLiteral value: Radian)

}

extension Radian: CustomStringConvertible, CustomDebugStringConvertible {

    var description: String {

        return self.value.description

    }

    var debugDescription: String {

        return "\(self.value.description)㎭"

    }

}

extension Radian: DegreeConvertiable {

    init(degreeLiteral value: Degree) {

        self.value = Double(degreeLiteral: value) * M_PI / 180.0

    }

    init(_ value: Degree) {

        self.init(degreeLiteral: value)

    }

}

//MARK:- Adding Conformance To Built In Types

extension FloatLiteralType: DegreeConvertiable, RadianConvertiable

{

    init(degreeLiteral degree: Degree) {

        self.value = degree.value.value

    }

    init(radianLiteral radian: Radian) {

        self.value = radian.value.value

    }

}

extension CGFloat: DegreeConvertiable, RadianConvertiable

{

    init(degreeLiteral degree: Degree) {

        self.init(degree.value)

    }

    init(radianLiteral radian: Radian) {

        self.init(radian.value)

    }

    init(_ degree: Degree) {

        self.init(degreeLiteral: degree)

    }

    init(_ radian: Radian) {

        self.init(radianLiteral: radian)

    }

}
--
 Wizard
james@supmenow.com
+44 7523 279 698
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
 Wizard
james@supmenow.com
+44 7523 279 698