[swift-evolution] Support for newtype feature/typesafe calculations

James Campbell james at supmenow.com
Wed Jan 6 11:15:52 CST 2016


I've managed to implement this already in the language with a few ugly
corners due to the lack of generic protocols.

I created a protocol based on Box (https://github.com/robrix/Box/) which
works really well. I have extended this to handle certain special protocols
like Equatable so you can do SpecialType == SpecialType, and even
literalConversion.

There is however a lot of boilerplate:

- You have to declare all of your Convertible protocols for converting from
one type to another
- You have to define an empty init so the protocol extensions have
something to chain to.
- You need to write the value property with type.

Due to the lack of protocol generics, you also need to have a protocol for
every type you wish to box which sets the associated type. Of course I
could have done this with classes but I wanted to keep this as a value type
:).

With member-wise initializations and generic protocols this could be
achievable just by adding a Box protocol to the standard library.

Here is my implementation of Box as a protocol:

*protocol Box: CustomStringConvertible, CustomDebugStringConvertible {*



*    typealias FloatLiteralType = Double*

*    typealias IntegerLiteralType = Int*

*    typealias BoxType = Any*



*    var value: BoxType { get set }*



*    init()*

*    init(_ value: BoxType)*

*}*


*extension Box where BoxType: CustomStringConvertible {*



*    var description: String {*

*        return self.value.description*

*    }*



*    var debugDescription: String {*

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

*    }*

*}*


*//MARK: FloatingPointBox*


*protocol FloatingPointBox: Box, FloatLiteralConvertible,
IntegerLiteralConvertible {*



*    typealias BoxType = Double*

*    typealias FloatLiteralConvertible = Double*

*    typealias IntegerLiteralConvertible = Int*

*}*


*extension Box where Self.BoxType == Double {*



*    init(_ value: Double) {*



*        self.init()*

*        self.value = value*

*    }*



*    init(_ value: Int) {*



*        self.init()*

*        self.value = Double(value)*

*    }*

*}*


*extension FloatLiteralType {*



*    init<T: Box where T.BoxType == Double >(_ box: T) {*

*        self.init(box.value)*

*    }*



*    init<T: Box where T.BoxType == Int >(_ box: T) {*

*        self.init(box.value)*

*    }*

*}*


*extension CGFloat {*



*    init<T: Box where T.BoxType == Double >(_ box: T) {*

*        self.init(box.value)*

*    }*



*    init<T: Box where T.BoxType == Int >(_ box: T) {*

*        self.init(box.value)*

*    }*

*}*


*//Adding FloatLiteralConvertible, IntegerLiteralConvertible*


*extension FloatingPointBox where Self.BoxType == Double,
Self.FloatLiteralConvertible == Double {*



*    init(floatLiteral value: Double) {*

*        self.init(value)*

*    }*



*    init(integerLiteral value: Int) {*

*        self.init(value)*

*    }*



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

*        self.init(value)*

*    }*

*}*

Here is my example of using the Box protocol:

*struct Degree: FloatingPointBox {*



*    var value: Double = 0*



*    init()*

*    {*

*    }*

*}*


*protocol DegreeConvertiable {*



*    init(degreeLiteral value: Degree)*

*}*


*extension Degree: RadianConvertiable {*



*    init(radianLiteral value: Radian) {*

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

*    }*



*    init(_ value: Radian) {*

*        self.init(radianLiteral: value)*

*    }*

*}*

On Tue, Jan 5, 2016 at 5:24 PM, Matthew Johnson via swift-evolution <
swift-evolution at swift.org> wrote:

>
> > On Jan 5, 2016, at 11:16 AM, Thorsten Seitz via swift-evolution <
> swift-evolution at swift.org> wrote:
> >
> >
> >> Am 05.01.2016 um 17:11 schrieb Grzegorz Adam Hankiewicz via
> swift-evolution <swift-evolution at swift.org>:
> >>
> >> The ideal would be for the compiler to pretend Euros or RefTablePk are
> different types, yet use their parent type at the binary level. This needs
> a specific syntax to teach the compiler which existing methods/operations
> are allowed on the new fake types and which aren’t. These new distinct
> types would *borrow* previous implementations.
> >
> > What about citing the relevant protocols in the newtype definition? This
> should include the ability to use my own protocols to which I have made the
> underlying type conform to by an extension.
>
> This is how my forwarding proposal works.  The newtype syntax I suggested
> as a possible extension looks like this:
>
> newtype Euro = Double forwarding Addable, Subtractable
>
> The keyword could be different, but I think `forwarding` is not bad.  When
> I complete the second draft I think it will make even more sense.  The
> forwarding facility has features to handle non-trivial cases (Self and
> associated type requirements, etc).
>
> >
> > Throwing some syntax into the discussion:
> >
> > newtype Euro = Double : Addable, Subtractable
> >
> > where I have defined the protocols Addable and Subtractable somewhere
> and made Double conform to them if all this is not provided by the standard
> library.
> > The implementation of Euro then borrows the implementation of Double for
> these protocols.
> >
> > -Thorsten
> > _______________________________________________
> > swift-evolution mailing list
> > swift-evolution at swift.org
> > https://lists.swift.org/mailman/listinfo/swift-evolution
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>



-- 
 Wizard
james at supmenow.com
+44 7523 279 698
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160106/ef1371cf/attachment-0001.html>


More information about the swift-evolution mailing list