Static Var closure returns Type.Type instead of Type - swift

I try to break, count and later join objects inside another class.
So I build protocol:
typealias DataBreaker<T> = () -> [Double]
typealias DataJoiner<T> = (_ particles: [Double]) -> T
protocol SpaceIntepolatable {
associatedtype Atom
var breaker:DataBreaker<Atom> {get}
static var joiner:DataJoiner<Atom> {get}
}
and build an extension for Point:
extension Point:SpaceIntepolatable {
typealias Atom = Point
var breaker:DataBreaker<Atom> {
return {
return [self.x, self.y]
}
}
static var joiner:DataJoiner<Atom> {
return {particles in
return Atom(x: particles[0], y: particles[1])
}
}
}
Till now is fine. I can break Point into an Array<Double>
let particles = atom.breaker()
but joining
let newAtom = Atom.joiner(particles)
causes a compiler error:
Cannot convert value of type 'Atom.Atom' to specified type 'Atom'
It's probably because joiner is a static. But how to avoid it and get Atom as a result?

You have to call it on Point when you are outside the scope of the class.
let newAtom = Point.joiner(particles)
Edit:
You say that you have a generic class that looks like this:
class Space<Atom: SpaceIntepolatable> {
func test() {
let particles: [Double] = [0, 1]
let newAtom: Atom = Atom.joiner(particles)
}
}
Now, the problem is that the type of newAtom is incorrect. The SpaceIntepolatable protocol doesn't specify that Point and Point.Atom are the same type. Therefore Atom (Point) and Atom.Atom (Point.Atom) are not considered the same. What we want is Atom.Atom. Or we can just let the type to be inferred:
let newAtom: Atom.Atom = Atom.joiner(particles)
let newAtom = Atom.joiner(particles)
In general it is advisable not to reuse type names because then you get things like Atom.Atom. Maybe you actually want something like this:
protocol SpaceIntepolatable {
var breaker: DataBreaker<Self> { get }
static var joiner: DataJoiner<Self> { get }
}
and lose the Atom typealias completely, then:
class Space<Atom: SpaceIntepolatable> {
func test() {
let particles: [Double] = [0, 1]
let newAtom: Atom = Atom.joiner(particles)
}
}
will actually work.

Related

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.

Assign value to a two-dimensional array in swift

I have a snippet of code like below:
protocol SomeProtocol {
}
struct SomeObject: SomeProtocol {
}
struct Test {
var arr: [[SomeProtocol]]
mutating func testFunction(objs:[[SomeObject]]) {
self.arr = objs
}
}
As you can see, SomeObject confirm the protocol, but the compiler shows me an
error " cannot assign value of type '[[SomeObject]]' to type '[[SomeProtocol]]'".
Can somebody tell me the reason?
Thanks a lot!
Because [[SomeObject]] is not the same type as [[SomeProtocol]] - see #TeeJay's comment above. The how is solved like this:
protocol SomeProtocol {
}
struct SomeObject: SomeProtocol {
}
struct Test {
var arr: [[SomeProtocol]]
mutating func testFunction(objs:[[SomeObject]]) {
self.arr = []
for a in objs {
var innerArray = [SomeProtocol]()
for e in a {
innerArray.append(e)
}
self.arr.append(innerArray)
}
}
}
Or, as #MartinR pointed out, you could use map.
If I try to short-circuit the inner loop with
self.arr = []
for a in objs {
self.arr.append(a)
}
I get the error "Cannot convert value of type 'Array&LT;SomeObject&GT;' to expected argument type [SomeProtocol]", which, on one level, is entirely correct - they are not the same - it's the elements, not the collection, which conform to the protocol. Array assignment doesn't dig down to the final element types for protocol conformance, unless you do it explicitly.
This is not entirely surprising - you wouldn't expect the following to work:
struct SomeOther1 {
var a : SomeProtocol
}
struct SomeOther2 {
var a : SomeObject
}
let x = SomeOther2(a: SomeObject())
let y: SomeOther1 = x // ERROR
whilst this should (and does) work:
let x = SomeOther2(a: SomeObject())
let y = SomeOther1(a: x.a)
Since Arrays are Structs that use generics, we can try the same using generics:
struct SomeOther<T> {
var a: T
}
let z = SomeOther<SomeObject>(a: SomeObject()) // OK, of course
let w = SomeOther<SomeProtocol>(a: SomeObject()) // OK, as expected
let v: SomeOther<SomeProtocol> = z // Doesn't work - types are not the same.