How to initialize Swift array with nil - swift

I am trying to have nil for zeroth index element and rest will have value of Generic type T which is Comparable.
So when I initialise it will nil it works as expected
struct Container<T: Comparable> {
var container = [T?]()
init() {
container.append(nil)
}
}
but when I do it with an integer say 0, I get ambiguous reference
struct Container<T: Comparable> {
var container = [T?]()
init() {
container.append(0)
}
}
Playground execution failed: error: Algorithms.playground:7:9: error: ambiguous reference to member 'append'
container.append(0)
^~~~~~~~~
I want to understand why this error is occurring?

The issue is that T: Comparable does not necessarily mean Int, it means ANY value that conforms to Comparable, which includes String, Float, Bool, and the thousands of custom structs other programmers have written for their own projects.
Since 0 is not a valid value for all of these Structs, you essentially have one of two issues:
1) Do I actually just want the Container to always use Int - in which case:
struct Container
{
var container: [Int?]
init()
{
container = [nil]
}
}
var a = Container()
a.container.append (0)
2) Why am I using 0, when I mean nil
struct Container<T: Comparable>
{
var container: [T?]
init()
{
container = [nil]
}
}
var a = Container<Int>()
a.container.append (0)

T can by any comparable type (String, a custom type, ...),
and initializing it from 0 is not generally
possible.
You could require that T can be created from an integer literal,
this covers all integer and floating point types:
struct Container<T: Comparable> where T: ExpressibleByIntegerLiteral {
var container = [T?]()
init() {
container.append(0)
}
}
Or provide a separate append() method:
struct Container<T: Comparable> {
var container = [T?]()
init() {
container.append(nil)
}
mutating func append(_ newElement: T) {
container.append(newElement)
}
}
var c = Container<Int>()
c.append(0)

Related

Use Protocol with associatedtype as a Type

I have the protocol like this
protocol ViewBuilder {
associatedtype In
associatedtype Out
func build(_ data: In?) -> Out?
}
I have the concrete struct like these. TitleTypeView and ButtonTypeView have the same super class.
struct HeaderTitleBuilder: ViewBuilder {
func build(_ data: DataSource?) -> ViewFactory? {
guard let data = data else { return nil }
return TitleTypeView(data)
}
}
struct HeaderButtonBuilder: ViewBuilder {
func build(_ data: DataSource?) -> ViewFactory? {
guard let data = data else { return nil }
return ButtonTypeView(data)
}
}
I have to combine the Builders struct into HeaderBuilder
struct TestStruct {
func create() {
HeaderBuilder(titleBuilder: HeaderTitleBuilder()
, seeallBuilder: HeaderButtonBuilder())
}
}
struct HeaderBuilder
{
private(set) var titleBuilder: some ViewBuilder = HeaderTitleBuilder()
private(set) var buttonBuilder: some ViewBuilder = HeaderButtonBuilder()
}
I got this error
Cannot convert value of type 'HeaderTitleBuilder' to expected argument type 'some ViewBuilder'
Cannot convert value of type 'HeaderButtonBuilder' to expected argument type 'some ViewBuilder'
So I try to use protocol as a generic constraint
struct HeaderBuilder <T: ViewBuilder>
where T.In == DataSource, T.Out == ViewFactory {
private(set) var titleBuilder: T = HeaderTitleBuilder()
private(set) var buttonBuilder: T = HeaderButtonBuilder()
}
DataSource and ViewFactory are all protocols without associatedtype.
I got this error.
Conflicting arguments to generic parameter 'T' ('HeaderTitleBuilder' vs. 'HeaderButtonBuilder')
I guess the compiler is using HeaderTitleBuilder and HeaderButtonBuilder to infer the type of T. But it is not what I want. I just need to T to be a protocol type that allows me to pass any Builder type.
Since ViewBuilder is a protocol, when you try make T a concrete type, it creates a conflict whether that type T is HeaderTitleBuilder or HeaderButtonBuilder. T cannot be both at the same time.
You can instead make both have a separate generic parameter, e.g,:
struct HeaderBuilder<TitleBuilder: ViewBuilder, ButtonBuilder: ViewBuilder> where TitleBuilder.In == DataSource, TitleBuilder.Out == ViewFactory, ButtonBuilder.In == DataSource, ButtonBuilder.Out == ViewFactory {
private(set) var titleBuilder: TitleBuilder
private(set) var buttonBuilder: ButtonBuilder
}

RangeReplaceableCollection conformance doesn't require... actually anything

According to the documentation:
To add RangeReplaceableCollection conformance to your custom
collection, add an empty initializer and the replaceSubrange(_:with:)
method to your custom type.
But in practice it's not required! (except for empty initializer)
// Just stubs for minimal reproducible code
struct Category: Hashable {}
struct Product {}
struct ProductCollection {
typealias DictionaryType = [Category : [Product]]
// Underlying, private storage
private var products = DictionaryType()
// Enable our collection to be initialized with a dictionary
init(products: DictionaryType = DictionaryType()) {
self.products = products
}
}
extension ProductCollection: Collection {
// Required nested types, that tell Swift what our collection contains
typealias Index = DictionaryType.Index
typealias Element = DictionaryType.Element
// The upper and lower bounds of the collection, used in iterations
var startIndex: Index { return products.startIndex }
var endIndex: Index { return products.endIndex }
// Required subscript, based on a dictionary index
subscript(index: Index) -> Iterator.Element {
get { return products[index] }
}
// Method that returns the next index when iterating
func index(after i: Index) -> Index {
return products.index(after: i)
}
}
extension ProductCollection: ExpressibleByDictionaryLiteral {
init(dictionaryLiteral elements: (Category, [Product])...) {
self.init(products: .init(uniqueKeysWithValues: elements))
}
}
extension ProductCollection: RangeReplaceableCollection {
init() {
products = DictionaryType()
}
// func replaceSubrange<C: Collection, R: RangeExpression>(_ subrange: R, with newElements: C)
// where Self.Element == C.Element, Self.Index == R.Bound {
// }
}
The code is taken from a great (but not related to the post's topic) John Sundell article.
This code compiles even though replaceSubrange function is not provided.
One more question. Why should I provide an empty initializer explicitly in this situation? I can initialize the struct like ProductCollection() without having that initializer. I can do this for many reasons: 1) products property has initializing value provided 2) main initializer has default value provided 3) there is also a ExpressibleByDictionaryLiteral initializer which can be used to initialize an empty object.
So why I have to provide one more empty initializer explicitly?
But please, the first question about replaceSubrange function is more important :)
That is a bug which has also been discussed in the Swift forum:
SR-6501 RangeReplaceableCollection default implementations cause infinite recursion
Compiler lets me use incomplete RangeReplaceableCollection
Using Swift
The reason is that there is an overload of the replaceSubRange() method (taking a RangeExpression as the first argument) which the compiler erroneously accepts as satisfying the protocol requirement.
But note that even if the code compiles without implementing the required method, it does not work and leads to an infinite loop. Here is a short example:
struct MyCollection : MutableCollection {
private var storage: [Int] = []
init(_ elements: [Int]) { self.storage = elements }
var startIndex : Int { return 0 }
var endIndex : Int { return storage.count }
func index(after i: Int) -> Int { return i + 1 }
subscript(position : Int) -> Int {
get { return storage[position] }
set(newElement) { storage[position] = newElement }
}
}
extension MyCollection: RangeReplaceableCollection {
init() { }
}
var mc = MyCollection([0, 1, 2, 3, 4, 5])
mc.replaceSubrange(0..<3, with: [2, 3, 4])
Running that code leads to an “infinite” loop and eventually crashes with EXC_BAD_ACCESS due to a stack overflow.

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()
}
}

Cannot use mutating member on immutable value of type

I have following struct:
public protocol SuperModel {
// empty protocol
}
struct ModelOne: SuperModel {
struct SubModelOne {
var someVar: Double
var othervar: Double?
}
var sub: SubModelOne?
mutating func setSub(sub: SubModelOne) {
self.sub = sub
}
}
In my class, I want to use this struct like that:
final class SomeClass: SuperClass {
var data: SuperModel
init() {
self.data = ModelOne()
}
func someFunc() {
(self.data as! ModelOne).setSub(ModelOne.SubModelOne(someVar: 2, otherVar: 1))
}
}
I get following error: Cannot use mutating member on immutable value of type 'ModelOne'. Why is that so and how can I fix this?
When you apply type casting to value types (such structs), if succeed, you receive immutable copy of requested value:
(self.data as! ModelOne) // this is copy of data
The only way (as known to me) how you can mutate values that need to be casted - reassign value (as #Sahil Beri pointed you need declare variable):
func someFunc() {
if var data = data as? ModelOne {
data.setSub(ModelOne.SubModelOne(someVar: 2, otherVar: 1))
self.data = data // you can do this since ModelOne conforms to SuperModel
}
}
Use like this,
struct UserAttributes {
var name:String?
var organizationID:String?
var email:String?
mutating func parseUserAttributes(attribues:[AWSCognitoIdentityProviderAttributeType])->UserAttributes{
for type in attribues{
if type.name == "name"{
name = type.value
}else if(type.name == "family_name"){
organizationID = type.value
}else if(type.name == "custom:role_id"){
role = type.value
}else if(type.name == "email"){
email = type.value
}
}
}
}
In some other file call like this,
var userAttributes = UserAttributes()
userAttributes = userAttributes.parseUserAttributes(attribues:attributes)
Problem is that you have declared data as SuperModel but allocate it as ModelOne. Declare data as ModelOne. Then the problem goes away.
final class SomeClass: SuperClass {
var data: ModelOne
init() {
self.data = ModelOne()
}
func someFunc() {
(self.data).setSub(ModelOne.SubModelOne(someVar: 2, otherVar: 1))
}
}
First downcast the self.data to ModelOne then call setSub function
if var data = self.data as? ModelOne {
data.setSub(ModelOne.SubModelOne(someVar: 2, othervar: 1))
}
#Shadow of is right. You try to mutate a temporary structure which is impossible and most of the time useless as it will be released once the mutation done. It's in fact a similar issue to trying to modify the return struct of a function. (see answer here : Cannot assign to property: function call returns immutable value)
In Swift 3, in my case, I was able to resolve the error just by changing struct to a class object.

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.