Hello, newcomer here.

The other day I was reading about 
https://www.reddit.com/r/swift/comments/3zbk64/type_math/ and given the verbose 
solutions decided to pitch a possible language improvement. But after reading 
through the archives it seems that this idea has already been pitched before:

* Proposal: newtype feature for creating brand new types from existing types

- 
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001821.html

- 
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001826.html

Some time later:

* Epic: Typesafe calculations

- 
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151228/004735.html

Since this is already known I would like to talk about this potential feature 
in order to address the perceived lack of community interest.

Recently I’ve been bitten by a lack of this feature for code dealing with 
database serialisation. If a database table is modelled as an object it will 
most likely use integers or longs to represent primary and foreign keys. An 
example would be:

struct SomeTable {
    var primaryKey: Int64
    var otherTableForeignKey: Int64
    var yeatAnotherForeginKey: Int64
}

Unfortunately the types can be mixed, one can assign the value from 
otherTableForeignKey to primaryKey without impunity. Using the reddit proposed 
struct as separate type would help here:

    public struct RefTablePk {
        private let value: Int64
    }

    public struct SomeTablePk {
        private let value: Int64
    }

    struct RefTable {
        var primaryKey: RefTablePk
    }

    struct SomeTable {
        var primaryKey = SomeTablePk(value: 0)
        var otherTableForeignKey = RefTablePk(value: 0)
    }

    var a = SomeTable()
    a.primaryKey = SomeTablePk(value: 3)
    a.otherTableForeignKey = a.primaryKey // Fails, good!
    print(a.primaryKey.value)

So far so good. The solution gets more hairy when one attempts to use such fake 
types for mathematical operations because the new type doesn’t inherit possible 
operations done on the parent type it is based of:

    public struct Euros {
        private let value: Double
    }

    public struct Dollars {
        private let value: Double
    }

    var account = Euros(value: 100)
    var bill = Euros(value: 42)
    account = account - bill

The last line won’t compile: Binary operator ‘-‘ cannot be applied to two 
‘Euros’ operands. The immediate solution would be to add variants of all the 
usual operators for every type, which quickly gets tedious and verbose. On top 
of this, each *new* type is generating code, which is actually not desirable. 
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.

Other examples of possible use for such fake types (note again: these exist 
only at compilation time and generate no extra code) would be user input 
validation. Strings coming from *the exterior* (whatever that might be) could 
use a distinct type of TaintedString instead of the usual String, and would 
require a validation or converter function to produce a correct String, or 
maybe a ValidatedString for better distinction. Similarly for a security 
library it would be useful to mark Strings as encrypted. The EncryptedString 
would be tracked by the compiler to prevent mistakes or uses where plaintext 
strings are expected. One bug I recently had the pleasure to solve was mixing 
time units, some APIs use seconds, other use milliseconds, both store the 
values as longs. The *fix* was to wrap all primitive type access inside objects 
with explicit methods having the unit in their signature. Effective, but 
tedious and verbose.

The typealias jumped out of the swift language documentation while I was 
reading it, but it is actually the opposite of the desired behaviour. The 
current type alias doesn’t prevent one from mixing these new fake types so it 
has effectively the same value as a user comment. Also, having seen 
https://github.com/apple/swift-evolution/blob/master/proposals/0011-replace-typealias-associated.md
 it seems that the keyword won’t be used any more, plus it would be convenient 
to invent a new one to avoid migration mistakes.

Examples I know of this feature in other languages and/or implementations which 
can be used for reference/inspiration:

- C++. I asked 
http://stackoverflow.com/questions/23726038/how-can-i-create-a-new-primitive-type-using-c11-style-strong-typedefs
 while following a talk by Bjarne Stroustrup and some of the answers include 
using boost units 
(http://www.boost.org/doc/libs/1_60_0/doc/html/boost_units/Units.html) to 
alleviate writing the required boilerplate code. The library was already 
mentioned here as reference in previous threads.

- Nim (http://nim-lang.org). Defined as distinct types 
(http://nim-lang.org/docs/manual.html#types-distinct-type) they can be used 
with the borrow pragma and templates to avoid boilerplate code yet customise 
which existing procs can be applied to the new distinct type.

- Java. The language doesn’t allow this kind of fake types, but it has been 
patched to various degrees through annotation support. Recently Android Studio 
added resource type annotations 
(http://tools.android.com/tech-docs/support-annotations#TOC-Resource-Type-Annotations)
 for mobile developers which allow marking integers with @StringRes, 
@IntegerRes and similar. The linter will look for these annotations and issue 
warnings when the assigned literals don’t satisfy the requirements. A more 
generic approach can be found in the Checker Framework in the Subtyping checker 
(http://types.cs.washington.edu/checker-framework/current/checker-framework-manual.html#subtyping-checker).
 The provided example shows how this hypothetical encrypted/plaintext string 
distinction would work. They also support the typical units annotations 
(http://types.cs.washington.edu/checker-framework/current/checker-framework-manual.html#units-checker).

Precisely this last reference is an argument against implementing this feature 
directly at the language level. I’ve seen that there is an attributes proposal 
(https://github.com/rsmogura/swift/wiki/Attributes-Proposal) which would 
provide the equivalent of java’s annotations. Given that Java has a checker 
framework it would surely make sense to implement this similarly in swift? I 
don’t think so. Essentially nobody I’ve worked with knows about such 
annotations or external tools (sad). While anecdotal, it’s easy for me to think 
that annotations are easy to brush off and forget.

And that’s why I’ve written this email, hopefully I can spur interest in others 
for this feature so that it becomes a first class citizen of the language at 
some point. I still haven’t got enough experience with swift to make a more 
concrete proposal. If nobody picks this up you may hear from me in the future.
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to