Requiring, for a protocol, that an instance variable conform to a protocol ; rather than have a specific type - swift

As part of a custom Coder, I convert both Float and Double in the exact same way :
static func encode(_ value : Double) -> Data {
withUnsafeBytes(of: value.bitPattern.bigEndian) { Data($0) }
}
static func encode(_ value : Float) -> Data {
withUnsafeBytes(of: value.bitPattern.bigEndian) { Data($0) }
}
I thought that instead I could require that value would conform to a protocol, and since the FloatingPoint protocol does not guarantee the presence of bitPattern, I thought I would make my own :
protocol CompatibleFloatingPoint {
var bitPattern : FixedWidthInteger { get }
}
This, however, gives the following error :
Protocol 'FixedWidthInteger' can only be used as a generic constraint because it has Self or associated type requirements
However, I cannot replace FixedWidthInteger with a specific type, as Double.bitPattern is a UInt64 and Float.bitPattern is a UInt32
What is the proper syntax to require that bitPattern conform to the FixedWidthInteger protocol without forcing it to have a specific type ?

What you're looking for is an associated type. This means exactly what you've described (the required type conforms to a protocol rather than being the existential of that protocol):
protocol CompatibleFloatingPoint {
associatedtype BitPattern: FixedWidthInteger
var bitPattern : BitPattern { get }
}
extension Float: CompatibleFloatingPoint {}
extension Double: CompatibleFloatingPoint {}
For more details, see Associated Types in the Swift Programming Language.

Related

Extentions for more than one protocol at once

I want to write extensions for more than one protocol and found this posting which was very interesting, but I wasn't able to follow Matthew Seaman completely.
In this case I want to write my own extension BinaryNumber which I want to add to BinaryInteger and BinaryFloatingPoint. But when I try to add my protocol, Xcode shows the error message Extension of protocol 'BinaryInteger' (or 'BinaryFloatingPoint') cannot have an inheritance clause.
Here is my code:
protocol BinaryNumbers {} // my protocol
extension BinaryNumbers {
func foo() -> Void {
print("It works!")
}
}
// try to extend Swift protocols
extension BinaryInteger : BinaryNumbers {} // doesn't work
extension BinaryFloatingPoint : BinaryNumbers {} // doesn't work
//Updade
#sweeper suggested to extend Numeric, so I tried, but get an error.
extension Numeric {
func foo() -> Bool {
return self <= 127
// Referencing operator function '<=' on 'BinaryInteger' requires
// that 'Self' conform to 'BinaryInteger'
}
}
When I extend BinaryInteger and BinaryFloatingPoint one by one, it works.
In general, it is not possible to write a single extension on multiple protocols. This would require the compiler to figure out the set intersection of all the members in all those protocols (those are the members you have access to in the extensions), which the compiler cannot do.
To avoid code duplication, you would need to work out the members that you need - in your case init(integerLiteral:) and <=, put those in your own protocol, and make the concrete types you want the extension to apply to, conform to your own protocol:
// inheriting from Comparable and ExpressibleByIntegerLiteral gives you the members you need
protocol BinaryNumbers : Comparable & ExpressibleByIntegerLiteral {
}
extension BinaryNumbers {
func atMost127() -> Bool {
self <= 127
}
}
extension Int: BinaryNumbers {}
extension Int8: BinaryNumbers {}
extension Int16: BinaryNumbers {}
extension Int32: BinaryNumbers {}
extension Int64: BinaryNumbers {}
// ... plus the unsigned versions, if you need them
extension Float16: BinaryNumbers {}
extension Float32: BinaryNumbers {}
extension Float64: BinaryNumbers {}
extension Float80: BinaryNumbers {}
Now you might ask, why don't we just make an extension of Comparable & ExpressibleByIntegerLiteral then, as they provide all the members we are using? Well, because that's not a nominal type, and you can't write extensions on non-nominal types :(
However, you could write it in this way:
// now you don't need your own "BinaryNumbers"!
extension Comparable where Self: ExpressibleByIntegerLiteral {
func atMost127() -> Bool {
self <= 127
}
}
You are only able to do this because the two members you need all came from protocols. If for some reason you need a member that both BinaryFloatingPoint and BinaryInteger has, but isn't provided by any of the protocols they conform to, then you need to write your own protocol with those members, and manually conform everything to that protocol.

How to solve the specification problem for Swift Protocol

protocol Specification {
associatedtype T
func isSatisfied(item : T) -> Bool
}
protocol AndSpecification {
associatedtype T
var arrayOfSpecs : [Specification] {set}
}
The aforementioned code gives the following error
Protocol 'Specification' can only be used as a generic constraint
because it has Self or associated type requirements
I understand that there is this problem because of associated types, which can be solved if I add a where clause. But I am at loss to understand where and how should I use this where clause
You think you need a where clause because you want the array to contain Specifications all with the same T, right? Well, protocols with associated types can't do that either!
What you can do is to have the array contain specifications all of the same type:
protocol AndSpecification {
associatedtype SpecificationType : Specification
var arrayOfSpecs : [SpecificationType] { get }
}
If you really like your T associated type, you can add one nonetheless:
protocol AndSpecification {
associatedtype T
associatedtype SpecificationType : Specification where SpecificationType.T == T
var arrayOfSpecs : [SpecificationType] { get }
}
But this is quite redundant, because you could just say AndSpecification.SpecificationType.T instead.

Abstract Access to Bitwise Shifts in Swift

So a little while ago I was working on some code in Swift that would allow me to do some useful extra manipulation of integers as binary, including getting the highest and lowest bits that are actually set.
As an example, here's a basic property I added that is now broken:
extension IntegerType {
var hiBit:Self { return ~self.allZeroes << ((sizeof(Self) * 8) - 1) }
}
This won't compile now because IntegerType no longer conforms to BitwiseOperationsType so the tilde operator and allZeroes properties are no longer available to it. Likewise there doesn't appear to be any requirement anymore for structs implementing IntegerType or BitwiseOperationsType to have shift operators, they just seem to be defined by convention now, unless I've missed something. This means that I can't transplant my code to BitwiseOperationsType either, even though it seems like the more logical place for it to be.
So my question is; where do I implement my code at the highest level? I don't want to have to duplicate it for every specific integer type, which is why I was extending IntegerType to begin with.
Also as an aside, I originally implemented hiBit as a static property, but these no longer appear to be supported, which is weird as they clearly were, and the error message implies that they will be in future, suggesting they were pulled from the spec; but I'm not running the Xcode beta.
There is no protocol which defines the bit shift operators, so you have
to define your own:
protocol ShiftOperationsType : BitwiseOperationsType {
func <<(lhs: Self, rhs: Self) -> Self
func >>(lhs: Self, rhs: Self) -> Self
init(_ value : Int)
}
Unfortunately, you have to declare the conformance of the integer type
to that protocol explicitly for each type (at present there is no
simpler solution, compare What protocol should be adopted by a Type for a generic function to take any number type as an argument in Swift?).
extension Int : ShiftOperationsType {}
extension Int8 : ShiftOperationsType {}
extension Int16 : ShiftOperationsType {}
extension Int32: ShiftOperationsType {}
extension Int64: ShiftOperationsType {}
extension UInt : ShiftOperationsType {}
extension UInt8 : ShiftOperationsType {}
extension UInt16 : ShiftOperationsType {}
extension UInt32 : ShiftOperationsType {}
extension UInt64 : ShiftOperationsType {}
But then you can define hiBit as a generic static property:
extension ShiftOperationsType {
static var hiBit : Self {
return (~allZeros) << Self(sizeof(Self) * 8 - 1)
}
}
The init method in the protocol is necessary because sizeof()
returns an Int and has to be converted to Self.

Statically typed properties in Swift protocols

I'm trying to use Protocol-Oriented Pgrogramming for model layer in my application.
I've started with defining two protocols:
protocol ParseConvertible {
func toParseObject() -> PFObject?
}
protocol HealthKitInitializable {
init?(sample: HKSample)
}
And after implementing first model which conforms to both I've noticed that another model will be basically similar so I wanted to create protocol inheritance with new one:
protocol BasicModel: HealthKitInitializable, ParseConvertible {
var value: AnyObject { get set }
}
A you can see this protocol has one additional thing which is value but I want this value to be type independent... Right now I have models which use Double but who knows what may show up in future. If I leave this with AnyObject I'm sentenced to casting everything I want to use it and if I declare it as Double there's no sense in calling this BasicModel but rather BasicDoubleModel or similar.
Do you have some hints how to achieve this? Or maybe I'm trying to solve this the wrong way?
You probably want to define a protocol with an "associated type",
this is roughly similar to generic types.
From "Associated Types" in the Swift book:
When defining a protocol, it is sometimes useful to declare one or
more associated types as part of the protocol’s definition. An
associated type gives a placeholder name (or alias) to a type that is
used as part of the protocol. The actual type to use for that
associated type is not specified until the protocol is adopted.
Associated types are specified with the typealias keyword.
In your case:
protocol BasicModel: HealthKitInitializable, ParseConvertible {
typealias ValueType
var value: ValueType { get set }
}
Then classes with different types for the value property can
conform to the protocol:
class A : BasicModel {
var value : Int
func toParseObject() -> PFObject? { ... }
required init?(sample: HKSample) { ... }
}
class B : BasicModel {
var value : Double
func toParseObject() -> PFObject? { ... }
required init?(sample: HKSample) { ... }
}
For Swift 2.2/Xcode 7.3 and later, replace typealias in the
protocol definition by associatedtype.

A common init function for all IntegerLiteralConvertible in Swift

I've currently made a protocol that has a bunch of redundant initializers
public protocol ConvertibleUnit {
///The raw value in `self` unit type
var value : Double { get set }
///The value in base units (i.e. for distance this would be `Meters`
var valueInBaseUnits : Double { get set }
///Do not interact with this directly
var data : UnitValueData { get set}
init(_ v : Double)
init(_ v : Float)
init(_ v : Int)
var unitType : ConversionEnum {get}
}
Basically I was hoping to make a protocol extension and define a default version of Float and Int
I tried some options (both of which error) similar to:
extension ConvertibleUnit {
init(_ v : Float) {
init(Double(v) )
}
init(_ v : Int) {
Self(Double(v))
}
}
This lead me to wonder if there was a common protocol such as IntegerLiteralConvertible that I could call the initializer with, but that also doesn't seem to work.
Basically is there a way to make (i guess a generic?) initializer that accepts anything that can be converted to a double and then will do a generic init.
init<T : ANYTHING_THAT_CAN_BE_CONVERTED_TO_DOUBLE>(_ v : T) {
let d : Double = Double(T)
// Do stuff to init
}
Update
tried using Self.init(Double(v))
You need to use self.init(...) (note the lowercase) when calling the initialiser:
extension ConvertibleUnit {
init(_ v: Int) {
self.init(Double(v))
}
init(_ v: Float) {
self.init(Double(v))
}
}
Inside the protocol extension try using Self.init(Double(v)). This will allow you to use a single initializer but get multiple from all conforming types. For more about using protocols and extensions read my blog post: http://manavgabhawala.me/#/blog/protocol-oriented-programming
Also, if you want to use generics there are two protocols you can use: FloatLiteralConvertible and FloatingPointType. You can find all protocols in the standard library here: https://developer.apple.com/library/prerelease/ios/documentation/General/Reference/SwiftStandardLibraryReference/#protocols
You can also use IntegerType and IntegerLiteralConvertible (which you mentioned).