Convert Objective-C (#define) macro to Swift - swift

Put simply I am trying to convert a #define macro into a native Swift data structure of some sort. Just not sure how or what kind.
Details
I would like to try and replicate the following #define from Objective-C to Swift. Source: JoeKun/FileMD5Hash
#define FileHashComputationContextInitialize(context, hashAlgorithmName) \
CC_##hashAlgorithmName##_CTX hashObjectFor##hashAlgorithmName; \
context.initFunction = (FileHashInitFunction)&CC_##hashAlgorithmName##_Init; \
context.updateFunction = (FileHashUpdateFunction)&CC_##hashAlgorithmName##_Update; \
context.finalFunction = (FileHashFinalFunction)&CC_##hashAlgorithmName##_Final; \
context.digestLength = CC_##hashAlgorithmName##_DIGEST_LENGTH; \
context.hashObjectPointer = (uint8_t **)&hashObjectFor##hashAlgorithmName
Obviously #define does not exist in Swift; therefore I'm not looking for a 1:1 port. More generally just the spirit of it.
To start, I made an enum called CryptoAlgorithm. I only care to support two crypto algorithms for the sake of this question; but there should be nothing stopping me from extending it further.
enum CryptoAlgorithm {
case MD5, SHA1
}
So far so good. Now to implement the digestLength.
enum CryptoAlgorithm {
case MD5, SHA1
var digestLength: Int {
switch self {
case .MD5:
return Int(CC_MD5_DIGEST_LENGTH)
case .SHA1:
return Int(CC_SHA1_DIGEST_LENGTH)
}
}
Again, so far so good. Now to implement the initFunction.
enum CryptoAlgorithm {
case MD5, SHA1
var digestLength: Int {
switch self {
case .MD5:
return Int(CC_MD5_DIGEST_LENGTH)
case .SHA1:
return Int(CC_SHA1_DIGEST_LENGTH)
}
var initFunction: UnsafeMutablePointer<CC_MD5_CTX> -> Int32 {
switch self {
case .MD5:
return CC_MD5_Init
case .SHA1:
return CC_SHA1_Init
}
}
}
Crash and burn. 'CC_MD5_CTX' is not identical to 'CC_SHA1_CTX'. The problem is that CC_SHA1_Init is a UnsafeMutablePointer<CC_SHA1_CTX> -> Int32. Therefore, the two return types are not the same.
Is an enum the wrong approach? Should I be using generics? If so, how should the generic be made? Should I provide a protocol that both CC_MD5_CTX and CC_SHA1_CTX and then are extended by and return that?
All suggestions are welcome (except to use an Objc bridge).

I don't know if I love where this is going in the original ObjC code, because it's pretty type-unsafe. In Swift you just need to make all the type unsafety more explicit:
var initFunction: UnsafeMutablePointer<Void> -> Int32 {
switch self {
case .MD5:
return { CC_MD5_Init(UnsafeMutablePointer<CC_MD5_CTX>($0)) }
case .SHA1:
return { CC_SHA1_Init(UnsafeMutablePointer<CC_SHA1_CTX>($0)) }
}
}
The more "Swift" way of approaching this would be with protocols, such as:
protocol CryptoAlgorithm {
typealias Context
init(_ ctx: UnsafeMutablePointer<Context>)
var digestLength: Int { get }
}
Then you'd have something like (untested):
struct SHA1: CryptoAlgorithm {
typealias Context = CC_SHA1_CONTEXT
private let context: UnsafeMutablePointer<Context>
init(_ ctx: UnsafeMutablePointer<Context>) {
CC_SHA1_Init(ctx) // This can't actually fail
self.context = ctx // This is pretty dangerous.... but matches above. (See below)
}
let digestLength = Int(CC_SHA1_DIGEST_LENGTH)
}
But I'd be strongly tempted to hide the context, and just make it:
protocol CryptoAlgorithm {
init()
var digestLength: Int { get }
}
struct SHA1: CryptoAlgorithm {
private var context = CC_SHA1_CTX()
init() {
CC_SHA1_Init(&context) // This is very likely redundant.
}
let digestLength = Int(CC_SHA1_DIGEST_LENGTH)
}
Why do you need to expose the fact that it's CommonCrypto under the covers? And why would you want to rely on the caller to hold onto the context for you? If it goes out of scope, then later calls will crash. I'd hold onto the context inside.
Getting more closely to your original question, consider this (compiles, but not tested):
// Digests are reference types because they are stateful. Copying them may lead to confusing results.
protocol Digest: class {
typealias Context
var context: Context { get set }
var length: Int { get }
var digester: (UnsafePointer<Void>, CC_LONG, UnsafeMutablePointer<UInt8>) -> UnsafeMutablePointer<UInt8> { get }
var updater: (UnsafeMutablePointer<Context>, UnsafePointer<Void>, CC_LONG) -> Int32 { get }
var finalizer: (UnsafeMutablePointer<UInt8>, UnsafeMutablePointer<Context>) -> Int32 { get }
}
// Some helpers on all digests to make them act more Swiftly without having to deal with UnsafeMutablePointers.
extension Digest {
func digest(data: [UInt8]) -> [UInt8] {
return perform { digester(UnsafePointer<Void>(data), CC_LONG(data.count), $0) }
}
func update(data: [UInt8]) {
updater(&context, UnsafePointer<Void>(data), CC_LONG(data.count))
}
func final() -> [UInt8] {
return perform { finalizer($0, &context) }
}
// Helper that wraps up "create a buffer, update buffer, return buffer"
private func perform(f: (UnsafeMutablePointer<UInt8>) -> ()) -> [UInt8] {
var hash = [UInt8](count: length, repeatedValue: 0)
f(&hash)
return hash
}
}
// Example of creating a new digest
final class SHA1: Digest {
var context = CC_SHA1_CTX()
let length = Int(CC_SHA1_DIGEST_LENGTH)
let digester = CC_SHA1
let updater = CC_SHA1_Update
let finalizer = CC_SHA1_Final
}
// And here's what you change to make another one
final class SHA256: Digest {
var context = CC_SHA256_CTX()
let length = Int(CC_SHA256_DIGEST_LENGTH)
let digester = CC_SHA256
let updater = CC_SHA256_Update
let finalizer = CC_SHA256_Final
}
// Type-eraser, so we can talk about arbitrary digests without worrying about the underlying associated type.
// See http://robnapier.net/erasure
// So now we can say things like `let digests = [AnyDigest(SHA1()), AnyDigest(SHA256())]`
// If this were the normal use-case, you could rename "Digest" as "DigestAlgorithm" and rename "AnyDigest" as "Digest"
// for convenience
final class AnyDigest: Digest {
var context: Void = ()
let length: Int
let digester: (UnsafePointer<Void>, CC_LONG, UnsafeMutablePointer<UInt8>) -> UnsafeMutablePointer<UInt8>
let updater: (UnsafeMutablePointer<Void>, UnsafePointer<Void>, CC_LONG) -> Int32
let finalizer: (UnsafeMutablePointer<UInt8>, UnsafeMutablePointer<Void>) -> Int32
init<D: Digest>(_ digest: D) {
length = digest.length
digester = digest.digester
updater = { digest.updater(&digest.context, $1, $2) }
finalizer = { (hash, _) in digest.finalizer(hash, &digest.context) }
}
}

Related

Swift, help iterating over keyPaths and setting values

I've found that it's a little easier to explain what I'm doing by giving too much context for why I'm trying to do it, sorry.
I'm currently trying to add an encryption service to my project. It's nothing that'll get published I think though and I've mostly got it working. The problem that I'm having is that I have my model like this
struct Entity {
// All types are examples though I think they will be all optionals.
var prop1: String?
var prop2: Int?
var prop3: Bool?
var encryptedData: [Keypath:EncryptedData]
static var encryptableKeyPaths: [WritableKeyPath<Entity, Any?>]
}
As an example for what's happening, I can get the encryptionService to take in prop1, create an EncryptedData and put it in the encryptedData dictionary. I can even get the keyPath for the property. I can encrypt all the data and decrypt it just fine and get all the values properly, so I don't need help with that. But I'm struggling with 3 issues.
Getting the KeyPaths to be WritableKeyPaths so I can write to them with the values I need.
Setting the properties to nil once the values are encrypted so I'm not storing extra data.
Setting the properties to their values once their decrypted.
All three of these issues seem to revolve around making the KeyPaths into WritableKeyPaths.
This is the closest attempt I've gotten so far. You can copy the following code right into a playground and run it and it should work. Except it'll crash at the end. There are a couple of issues here, I'm losing the type safety as I have to make all the property types Initializable? which isn't great. Also, see that the values are permanently wrapped. I can't figure out how to prevent that. I had to mark Optional as conforming to Initializable to make this work. Lastly, the variable allStoredProperties doesn't let me write to them. I'm not sure how to properly convert it to WritableKeyPath from PartialKeyPath.
import UIKit
protocol Initializable {}
extension String: Initializable {}
extension Int: Initializable {}
extension Bool: Initializable {}
extension Optional: Initializable {}
protocol KeyPathIterable {
associatedtype Model
init()
static var allKeyPaths: [WritableKeyPath<Model, Initializable?>] { get }
}
extension KeyPathIterable {
var keyPathReadableFormat: [String: Initializable] {
var description: [String: Initializable] = [:]
let mirror = Mirror(reflecting: self)
for case let (label?, value) in mirror.children {
description[label] = (value as! Initializable)
}
return description
}
static var allStoredProperties: [PartialKeyPath<Self>] {
var members: [PartialKeyPath<Self>] = []
let instance = Self()
for (key, _) in instance.keyPathReadableFormat {
members.append(\Self.keyPathReadableFormat[key])
}
return members
}
static func setValue<Self: KeyPathIterable, T: Initializable>(on root: inout Self,
at keyPath: WritableKeyPath<Self, Initializable?>,
withValue value: T?) throws {
root[keyPath: keyPath] = value
}
}
struct Foo: KeyPathIterable {
typealias Model = Foo
var prop1: Initializable? // I want this to be String?
var prop2: Initializable? // I want this to be Int?
var prop3: Initializable? // I want this to be Bool?
init() {
self.prop1 = nil
self.prop2 = nil
self.prop3 = nil
}
static var allKeyPaths: [WritableKeyPath<Foo, Initializable?>] {
return [\Model.prop1, \Model.prop2, \Model.prop3]
}
}
var foo = Foo()
foo.prop1 = "Bar"
foo.prop2 = 1
foo.prop3 = true
print(foo.prop1 as Any)
let keyPath = \Foo.prop1
foo[keyPath: keyPath] = "Baz"
print(foo.prop1 as Any)
for path in Foo.allStoredProperties {
print("-=-=-")
print(path)
}
print("-=-=-=-=-=-=-=-")
do {
try Foo.setValue(on: &foo, at: keyPath, withValue: "BazBar" as Initializable?)
} catch {
print("Should never fail")
}
print(foo.prop1 as Any) // Returns Optional(Optional("BarBaz")) - I want this to be all the way unwrapped.
print("--------------")
let values1: [Initializable] = ["Hello World", 100, false]
do {
for (path, value) in zip(Foo.allKeyPaths, values1) {
try Foo.setValue(on: &foo,
at: path,
withValue: value as Initializable?)
}
} catch {
print("Success?")
}
print(foo.prop1 as Any)
print(foo.prop2 as Any)
print(foo.prop3 as Any)
print("----====----====----")
let values2: [Initializable] = ["Howdy", 0, false]
do {
for (path, value) in zip(Foo.allStoredProperties, values2) {
try Foo.setValue(on: &foo,
at: path as! WritableKeyPath<Foo, Initializable?>,
withValue: value as Initializable?)
}
} catch {
print("Always fails")
}
print("=-=-=-=-=-=-=-=")
print(foo)
I've looked all over google and youtube and everywhere and I can't seem to get this to work. I'm open to a different architecture if that work accomplish my goals better. Just a little frustrated. Thanks for your help.

How to use type-erase in Swift

Story:
I have some layouts.
A layout have a pattern and keys. The layout can make message from these.
Each patterns have maximum number of keys.
That is my code to expression templates.
protocol LayoutPattern {
static var numberOfKeys: Int { get }
static func make(with keys: [String]) -> String
}
struct Pattern1: LayoutPattern {
static let numberOfKeys: Int = 1
static func make(with keys: [String]) -> String {
return "Pattern 1:" + keys.joined(separator: ",")
}
let value1: String
}
struct Pattern2: LayoutPattern {
static let numberOfKeys: Int = 2
static func make(with keys: [String]) -> String {
return "Pattern 2:" + keys.joined(separator: ",")
}
let value1: String
let value2: String
}
protocol LayoutProtocol {
associatedtype Pattern: LayoutPattern
var keys: [String] { get }
func make() -> String
}
struct Layout<T: LayoutPattern>: LayoutProtocol {
typealias Pattern = T
let keys: [String]
init(keys: [String]) {
assert(keys.count == Pattern.numberOfKeys)
self.keys = keys
}
func make() -> String {
return Pattern.make(with: keys)
}
}
let t1 = Layout<Pattern1>(keys: ["key1"])
t1.make() // Pattern 1: key1
let t2 = Layout<Pattern2>(keys: ["key1", "key2"])
t2.make() // Pattern 2: Key1,Key2
This is valid code.
But I can't write that:
class MyNote {
let layout: LayoutProtocol
}
I know that I should use a technique called type-erase like AnyPokemon!
I wrote that:
struct AnyLayout<T: LayoutPattern>: LayoutProtocol {
typealias Pattern = T
let keys: [String]
private let _make: () -> String
init<U: LayoutProtocol>(_ layout: U) where T == U.Pattern {
self.keys = layout.keys
self._make = { layout.make() }
}
func make() -> String {
_make()
}
}
let anyLayout = AnyLayout(Layout<Pattern2>(keys: ["key1", "key2"]))
anyLayout.make() // Pattern 2: Key1,Key2
This can be executed. But MyNote class can't still have a property as AnyLayout.
What should I do?
The issue is the addition of the associatedtype. It isn't doing any work here. Nothing relies on it. Remove it, and the issue goes away. Don't add associatedtypes until you have a specific requirement for them.
As a rule, if you think you need type-erasure, first ask if your protocol is designed correctly. There are definitely times that type erasers are needed, but they're far rarer than people expect.
If you have an algorithm that relies on Pattern, then show that, and we can discuss the way to build that. (There are many techniques, including using multiple protocols.)
It's also worth asking whether Layout needs to be generic here. Do you want Layout<Pattern1> to be a different type than Layout<Pattern2>? The fact that you're then trying to type-erase it suggests you don't. In that case, there's no reason for the extra generic layers. In your example, Layout isn't really doing any work. Again, you can probably just get rid of it. Let each pattern be its own thing and let Layout be a protocol that binds them with make():
protocol Layout {
func make() -> String
}
struct Pattern1: Layout {
let key: String
func make() -> String {
return "Pattern 1:" + key
}
}
struct Pattern2: Layout {
let keys: [String]
init(key1: String, key2: String) {
keys = [key1, key2]
}
func make() -> String {
return "Pattern 2:" + keys.joined(separator: ",")
}
}
let t1 = Pattern1(key: "key1")
t1.make() // Pattern 1: key1
let t2 = Pattern2(key1: "key1", key2: "key2")
t2.make() // Pattern 2: Key1,Key2
class MyNote {
let layout: Layout
init(layout: Layout) {
self.layout = layout
}
}
let note = MyNote(layout: t1)
This lets you make your Pattern initializers much stronger types. The need for an assert means you're not letting the types do the work. With the above design, you can't pass the wrong number of keys.

Extension optional Array with Optional Element. Is it even possible?

I have a protocol FooProtocol. and a class Bar<Foo:FooProtocol>. Inside a class an Array var mess: [Foo?]? to keep [foo1, foo2, nil, foo3...] or nil
And I try to make extension for this array to count new Foo object. I prefer to have protocols, because Foos could be very different objects delivered from outer world.
protocol FooProtocol {
....
init(from heaven: Int)
}
extension Optional where
Wrapped: Collection,
Wrapped.Element == Optional,
Wrapped.Element.Wrapped: FooProtocol // 'Wrapped' is not a member type of 'Wrapped.Element'
{
var united: Wrapped.Element.Wrapped { // Nope
let i = ...
return Wrapped.Element.Wrapped(from: i) // Nope
}
}
class Bar<Foo:FooProtocol> {
var mess: [Foo?]?
init (with mess: [Foo?]?) {
self.mess = mess
}
var important: Foo {
return mess.united
}
}
Any ideas? I'm blocked.
Edit 1:
After Leo suggestions I changed some parts of my code. But still stucked. This time more code from Playgrounds.
Any object that could be converted into '[Double]'. Could be color (as RGBA), Bezier curve, square, whatever...
public protocol FooProtocol {
var atomized: () -> [Double] {get}
static var count: Int {get}
init(_ array:[Double])
init()
}
public extension Array where Element: FooProtocol {
var average: Element {
var resultAtoms: [Double] = []
let inputAtoms = self.map {$0.atomized()}
for i in 0..<Element.count {
let s = inputAtoms.reduce(into: 0.0, {$0 += $1[i]}) / Double (Element.count)
resultAtoms.append(s)
}
return Element(resultAtoms)
}
}
extension Optional where
Wrapped: Collection,
Wrapped.Element == Optional<FooProtocol>
{
typealias Foo = Wrapped.Element.Wrapped // Doesn't work. How to get class?
var average: Foo { // I cannot use Wrapped.Element, it's Optional
if let thatsList = self {
let withOptionals = Array(thatsList) // OK, its [Optional<FooProtocol>]
let withoutOptionals = thatsList.compactMap({$0}) // OK, its [FooProtocol]
// This is funny, called from class works and makes 'bingo'.
return withoutOptionals.average // Error: Value of protocol type 'FooProtocol' cannot conform to 'FooProtocol'; only struct/enum/class types can conform to protocols
} else {
return Foo() // Hello? init Wrapped? Foo? How to get Foo()?
}
}
}
class Bar<Foo:FooProtocol> {
var mess: [Foo?]?
init (with mess: [Foo?]?) {
self.mess = mess
}
func workOn() {
let z:Foo = mess.average // OK, I can make 'mess.average ?? Foo()' but prefer not do it
}
// Thats OK
func workHard() { // To prove 'Array extension where Element: FooProtocol' works
if let messExist = mess {
let withoutOptionals = messExist.compactMap({$0})
let bingo = withoutOptionals.average //It's OK
}
}
}
class SomeFoo : FooProtocol {
static var count = 3
required init() {
a = 0
b = 0
c = 0
}
required init(_ array: [Double]) {
self.a = Int(array[0])
self.b = Float(array[1])
self.c = array[2]
}
var atomized: () -> [Double] {
return {return [Double(self.a), Double(self.b), self.c]}
}
var a: Int
var b: Float
var c: Double
}
let aFoo = SomeFoo([1, 2, 3])
let bFoo = SomeFoo([7, 9, 1])
let cFoo = SomeFoo([2, 6, 5])
let barData = [nil, aFoo, nil, bFoo, cFoo]
let barWithData = Bar(with: barData)
let barWithoutData = Bar<SomeFoo>(with: nil)
Maybe I should forget about extending array and make some functions inside a class (I'm almost sure I will need those functions somewhere else)
Edit 2
Even if I try to simplify and to make extension for Array I found troubles.
extension Array where
Element == Optional<FooProtocol>
{
func averageNils <Foo: FooProtocol>() -> Foo {
let withOptionals = Array(self) // OK, its [Optional<FooProtocol>]
let withoutOptionals = self.compactMap({$0}) // OK, its [FooProtocol]
return withoutOptionals.average as! Foo // Error: Value of protocol type 'FooProtocol' cannot conform to 'FooProtocol'; only struct/enum/class types can conform to protocols
}
}
From my understanding, it should work as you did, but one never knows what happens in the swift compiler world (and especially it's error messages).
Anyway, you can circumvent digging deeper into Wrapped.Element.Wrapped by specifyig the Wrapped.Element more precisely to be an Optional<FooProtocol>:
protocol FooProtocol {}
class Foo : FooProtocol {}
extension Optional where
Wrapped: Collection, //OK
Wrapped.Element == Optional<FooProtocol> // still good
{
var unfied: Wrapped.Element // Should be 'Foo' if self is '[Foo?]?' {
{
return 1 == 0 ? nil : Foo()
}
}

Linked list declaration in Swift with finger type that can transparently insert in either middle or start

I am attempting to declare a linked list in Swift, with a finger type that is a reference to either a node, allowing to insert or remove beyond that node, or to the linked list itself, in which case inserting or removing at the top of the linked list.
I want to see if this can be made uniform down to the implementation, instead of having to special-case everything: Swift is object-oriented, after all.
I previously had a version which required forced casts, but again I'd like to see if this can be made to work without them (e.g. even if they never end up faulting they still imply runtime checks each time).
I currently have this code:
protocol ContainerNodeInterface: class {
associatedtype ContainedItem;
var contents: ContainedItem { get };
}
protocol ParentNodeInterface: class {
associatedtype LinkedItem: ContainerNodeInterface;
var next: LinkedItem? {get set};
}
class ProtoNode<Contents, NodeType: ParentNodeInterface>: ParentNodeInterface where NodeType.ContainedItem==Contents, NodeType.LinkedItem==NodeType { // not meant to be instantiated or directly referenced
typealias LinkedItem = NodeType;
var next: NodeType?;
init() {
next = nil;
}
final func insertThisAfterMe(_ node: NodeType) {
node.next = next;
next = .some(node);
}
final func removeNodeAfterMe() -> NodeType? {
guard let nextNode = next else {
return nil;
}
let result = nextNode;
next = result.next;
result.next = nil;
return nextNode;
}
}
class Node<Contents>: ProtoNode<Contents, Node<Contents>>, ContainerNodeInterface {
typealias ContainedItem = Contents;
typealias NextItem = Node<Contents>;
var contents: Contents;
init(withContents: Contents) {
contents = withContents;
super.init();
}
}
typealias ParentNode<Contents> = ProtoNode<Contents, Node<Contents>>;
But the Swift compiler, via Xcode, is complaining that Type 'Node<Contents>' does not conform to protocol 'ParentNodeInterface'. This makes no sense! And if I add explicit conformance to ParentNodeInterface to Node, then I get simultaneously that error and one of redundant conformance to the same protocol.
What is missing here?
Xcode Version 10.2 (10E125), Swift 5
I resolved it by splitting ProtoNode into an initial declaration and an extension:
protocol ContainerNodeInterface: class {
associatedtype ContainedItem;
var contents: ContainedItem { get };
}
protocol ParentNodeInterface: class {
associatedtype LinkedItem: ContainerNodeInterface;
var next: LinkedItem? {get set};
}
class ProtoNode<Contents, NodeType: ContainerNodeInterface>: ParentNodeInterface where NodeType.ContainedItem==Contents { // not meant to be instantiated or directly referenced
typealias LinkedItem = NodeType;
var next: NodeType?;
init() {
next = nil;
}
}
extension ProtoNode where NodeType: ParentNodeInterface, NodeType.LinkedItem==NodeType
{
final func insertThisAfterMe(_ node: NodeType) {
node.next = next;
next = .some(node);
}
final func removeNodeAfterMe() -> NodeType? {
guard let nextNode = next else {
return nil;
}
let result = nextNode;
next = result.next;
result.next = nil;
return nextNode;
}
}
class Node<Contents>: ProtoNode<Contents, Node<Contents>>, ContainerNodeInterface {
typealias ContainedItem = Contents;
typealias NextItem = Node<Contents>;
var contents: Contents;
init(withContents: Contents) {
contents = withContents;
super.init();
}
}
typealias ParentNode<Contents> = ProtoNode<Contents, Node<Contents>>;
I figure it helps the compiler break the dependency loop, where it has to determine whether Node, as a generic parameter, conforms to the protocol before it can determine the declaration is valid and consider the declared type, i.e. Node, as conforming to the protocol, but still it feels a bit silly for me to have to make this seemingly pointless extension declaration.
At the very least, the compiler could be slightly more helpful…
First, I would start with a simple linked-list Node type:
final class Node<Value> {
let value: Value
var next: Node<Value>?
init(_ value: Value) {
self.value = value
}
func insert(_ node: Node<Value>) {
node.next = next
next = node
}
func removeNext() -> Node<Value>? {
guard let removedNode = next else { return nil }
next = removedNode.next
removedNode.next = nil
return removedNode
}
}
Then, you can add the concept that you describe: a pointer to "either a node...or to the linked list itself." When you see "or" in a description, that implies a sum type, which in Swift is an enum, either a pointer to the head of a (possibly empty) list, or a pointer to a node. Each has slightly different behaviors, which you manage with switch.
enum NodePointer<Value> {
case head(Node<Value>?)
case node(Node<Value>)
mutating func insert(_ node: Node<Value>) {
switch self {
case .head(let n):
self = .head(node)
node.next = n
case .node(let n):
n.insert(node)
}
}
mutating func removeNext() -> Node<Value>? {
switch self {
case .head(let n):
self = .head(n?.next)
return n
case .node(let n):
return n.removeNext()
}
}
var pointee: Node<Value>? {
switch self {
case .head(let n): return n
case .node(let n): return n
}
}
}
With that you would have an interface like:
var list = Node(1)
list.insert(Node(2))
var ptr = NodePointer.head(list)
ptr.insert(Node(1))
ptr.pointee?.next?.next?.value // 2
Note that the specific problem you ran into (that the compiler couldn't work out the conformance) I believe is a compiler bug, though I also believe it's one that's fixed on master currently. I haven't tested that out though. But I don't believe the protocol-based approach is correct for this problem.

Can you simultaneously define and instantiate implicit types in Swift?

Just messing around with the language thinking of how I want to structure some UserDefaults that automatically generate keys based on the hierarchy. That got me wondering... Is it possible to simultaneously define, and instantiate a type, like this?
let myUserSettings = {
let formatting = {
var lastUsedFormat:String
}
}
let lastUsedFormat = myUserSettings.formatting.lastUsedFormat
Note: I can't use statics because I specifically need instancing so nested structs/classes with static members will not work for my case.
Here's the closest thing I could come up with, but I hate that I have to create initializers to set the members. I'm hoping for something a little less verbose.
class DefaultsScope {
init(_ userDefaults:UserDefaults){
self.userDefaults = userDefaults
}
let userDefaults:UserDefaults
func keyForSelf(property:String = #function) -> String {
return "\(String(reflecting: self)).\(property)"
}
}
let sharedDefaults = SharedDefaults(UserDefaults(suiteName: "A")!)
class SharedDefaults : DefaultsScope {
override init(_ userDefaults:UserDefaults){
formatting = Formatting(userDefaults)
misc = Misc(userDefaults)
super.init(userDefaults)
}
let formatting:Formatting
class Formatting:DefaultsScope {
let maxLastUsedFormats = 5
fileprivate(set) var lastUsedFormats:[String]{
get { return userDefaults.stringArray(forKey:keyForSelf()) ?? [] }
set { userDefaults.set(newValue, forKey:keyForSelf()) }
}
func appendFormat(_ format:String) -> [String] {
var updatedListOfFormats = Array<String>(lastUsedFormats.suffix(maxLastUsedFormats - 1))
updatedListOfFormats.append(format)
lastUsedFormats = updatedListOfFormats
return updatedListOfFormats
}
}
let misc:Misc
class Misc:DefaultsScope {
var someBool:Bool{
get { return userDefaults.bool(forKey:keyForSelf()) }
set { userDefaults.set(newValue, forKey:keyForSelf()) }
}
}
}
So is there a simpler way?
Disclaimer: this is, probably, just an abstract solution that should not be used in real life :)
enum x {
enum y {
static func success() {
print("Success")
}
}
}
x.y.success()
Update: Sorry, folks, I can't stop experimenting. This one looks pretty awful :)
let x2= [
"y2": [
"success": {
print("Success")
}
]
]
x2["y2"]?["success"]?()
Update 2: One more try, this time with tuples. And since tuples must have at least two values, I had to add some dummies in there. Also, tuples cannot have mutating functions.
let x3 = (
y3: (
success: {
print("Success")
},
failure: {
print("Failure")
}
),
z3: 0
)
x3.y3.success()
How about you try nesting some swift structs?
struct x {
struct y {
static func success() {
print("success")
}
}
}
x.y.success()
You cannot have that kind of structure but you cant access y from inside x, since y is only visible inside the scope of x and so is success inside the scope of y. There is no way that you can access them from outside
One other alternative is to have higher order function like so, which return closure which is callable.
let x = {
{
{
print("Success")
}
}
}
let y = x()
let success = y()
success()
or
x()()()
The real world usage of higher order function for userdefaults could be something like this,
typealias StringType = (String) -> ((String) -> Void)
typealias IntType = (String) -> ((Int) -> Void)
typealias BoolType = (String) -> ((Bool) -> Void)
typealias StringValue = (String) -> String?
typealias IntValue = (String) -> Int?
typealias BoolValue = (String) -> Bool?
func userDefaults<T>(_ defaults: UserDefaults) -> (String) -> ((T) -> Void) {
return { key in
return { value in
defaults.setValue(value, forKey: key)
}
}
}
func getDefaultsValue<T>(_ defaults: UserDefaults) -> (String) -> T? {
return { key in
return defaults.value(forKey: key) as? T
}
}
let setStringDefaults: StringType = userDefaults(.standard)
setStringDefaults("Name")("Jack Jones")
setStringDefaults("Address")("Australia")
let setIntDefaults: IntType = userDefaults(.standard)
setIntDefaults("Age")(35)
setIntDefaults("Salary")(2000)
let setBoolDefaults: BoolType = userDefaults(.standard)
setBoolDefaults("Married")(false)
setBoolDefaults("Employed")(true)
let getStringValue: StringValue = getDefaultsValue(.standard)
let name = getStringValue("Name")
let address = getStringValue("Address")
let getIntValue: IntValue = getDefaultsValue(.standard)
let age = getIntValue("Age")
let salary = getIntValue("Salary")
let getBoolValue: BoolValue = getDefaultsValue(.standard)
let married = getBoolValue("Married")
let employed = getBoolValue("Employed")
I am not sure if you like the pattern, but it has some good use cases as you can see from below, setStringDefaults you can set strings value to string key and all of them are typesafe.
You can extend this for your use case. But, you could use struct as well and use imperative code, which could be easier to understand. I see beauty in this as well.
Ok, I think I've figured it out. This first class can go in some common library that you use for all your apps.
class SettingsScopeBase {
private init(){}
static func getKey(setting:String = #function) -> String {
return "\(String(reflecting:self)).\(setting)"
}
}
The next part is a pair of classes:
The 'Scoping' class where you define which user defaults instance to use (along with anything else you may want to specify for this particular settings instance)
The actual hierarchy that defines your settings
Here's the first. I'm setting this up for my shared settings between my application and it's extension:
class SharedSettingsScope : SettingsScopeBase{
static let defaults = UserDefaults(suiteName: "group.com.myco.myappgroup")!
}
And finally, here's how you 'set up' your hierarchy as well as how you implement the properties' bodies.
class SharedSettings:SharedSettingsScope{
class Formatting:SharedSettingsScope{
static var groupsOnWhitespaceOnlyLines:Bool{
get { return defaults.bool(forKey: getKey()) }
set { defaults.set(newValue, forKey: getKey()) }
}
}
}
And here's how you use them...
let x = SharedSettings.Formatting.groupsOnWhitespaceOnlyLines
// x = false
SharedSettings.Formatting.groupsOnWhitespaceOnlyLines = true
let y = SharedSettings.Formatting.groupsOnWhitespaceOnlyLines
// y = true
I'm going to see if I can refine/optimize it a little more, but this is pretty close to where I want to be. No hard-coded strings, keys defined by the hierarchy where they're used, and only setting the specific UserDefaults instance in one place.