7

I'm playing around with Swift trying to make it look more "dynamically typed" – just for fun, no production value expected.

Now I'm stuck with overwriting behavior of converting builtin types to String.

For example, I'd like to see this output for Array:

let nums = [1, 2, 3]
print(nums) // "I'm an array"

So far I tried to

  • make an extension to NSArray (not compiles)
  • implement CustomStringConvertible (not compiles)
  • make an extension to Array (compiles, changes nothing)

Seems like I'm on the wrong path:

extension Array: CustomStringConvertible {
    public var description: String { return "An array" }
}

gives the warning:

Conformance of 'Array' to protocol 'CustomStringConvertible' was already stated in the type's module 'Swift'

Is this doable in Swift?

11
  • You are right to implement CustomStringConvertible, maybe show that code, here is an example: var description:String { var desc = "Array: [" for ite, in items { desc += "(item)" + ", " } return desc + "]" } Commented Aug 19, 2016 at 20:05
  • As I've written above, implementing CustomStringConvertible for an Array does not compiles with an error: Redundant conformance of 'Array<Element>' to protocol 'CustomStringConvertible'. Commented Aug 19, 2016 at 20:09
  • Implement your Array that inherits from Array and conforms to CustomStringConvertible. Commented Aug 19, 2016 at 20:11
  • "Inheritance from non-protocol, non-class type 'Array'" if I'm trying to do so. Commented Aug 19, 2016 at 20:14
  • You cannot subclass Array because it is a struct. See: stackoverflow.com/questions/26289413/… Commented Aug 19, 2016 at 20:15

3 Answers 3

5

This does not work because Array overrides description. If array did not override it then it would print "An array". The class method 'wins' over the extension.

extension Array {
    public var description: String { return "An array" }
}

You could create a Wrapper class for your array. It's a workaround but doesn't override array's description itself.

class ArrayWrapper<T> : CustomStringConvertible{
    var array : Array<T> = Array<T>()
    var description: String { return "An array" }
}

You could then use it like this.

var array = ArrayWrapper<Int>()
array.array = [1,2,3]
print(array) //prints "An Array"
print(array.array) //still prints "[1, 2, 3]"
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the insight!
0

Seems like it is not possible to neither subclass nor overwrite a builtin Array type.

We could use a wrapper though (credits to @Yannick) and implement a ArrayLiteralConvertible protocol, so we could use square brackets for initialization.

struct Array<T> {
    let array: [T]
}

extension Array: ArrayLiteralConvertible {
    init(arrayLiteral elements: T...) {
        self.array = elements
    }
}

extension Array: CustomStringConvertible {
    var description: String { return "An array" }
}

let array = [1,2,3]
print(array) // "An array\n"

Comments

0

Swift does not allow you to provide a protocol override for a type that already declares that protocol:

Imagine that you have a set of integers and you want to override the default implementation of CustomStringConvertible for a Set

The simplest answer to all of this is: you can't, and that's a feature not a bug. Set isn't your type and you don't get to change its already-defined behavior like this.

The capability to intercept and alter the behavior of a type to do something different to what that type is originally designed to do is powerful, but fraught with downsides. In this case, you've chosen a fairly benign thing to alter, but in other cases doing this could do all sorts of damage to assumed invariants of a type by changing its program-wide behavior.

The best way to alter a type to do something different like this is to wrap it in your own low-cost struct. Unfortunately this does mean writing a fair amount of boilerplate for forwarding – though less and less these days as we gain features like synthesized conformances and dynamic member lookup. Hopefully someday we'll get features that do make easier to create a newtype with customized behavior.

https://forums.swift.org/t/whats-the-best-way-to-override-customstringconvertible-for-a-collection/24844

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.