Customizing my custom type's appearance in the debugger


(Tim Vermeulen) #1

I’ve implemented a linked list. Now I’d like to be able to view the elements of a linked list in the debugger just like with an array. In the debugger, an array is represented like this:

[0] = the first element
[1] = the second element
etc

I wonder if I can do the same for my linked list. I already implemented CustomReflectable, so the code `dump(myLinkedList)` shows this in the console:

3 elements
  - first element
  - second elements
  - third element

I thought this would also change the appearance of my linked list in the debugger, but unfortunately it’s unchanged. Is there a way to do what I’m trying to do?


(Dmitri Gribenko) #2

Try setting "displayStyle: .collection" when you call the Mirror initializer.

Dmitri

···

On Fri, Jun 24, 2016 at 3:53 PM, Tim Vermeulen via swift-users <swift-users@swift.org> wrote:

I’ve implemented a linked list. Now I’d like to be able to view the elements of a linked list in the debugger just like with an array. In the debugger, an array is represented like this:

[0] = the first element
[1] = the second element
etc

I wonder if I can do the same for my linked list. I already implemented CustomReflectable, so the code `dump(myLinkedList)` shows this in the console:

3 elements
  - first element
  - second elements
  - third element

I thought this would also change the appearance of my linked list in the debugger, but unfortunately it’s unchanged. Is there a way to do what I’m trying to do?

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Tim Vermeulen) #3

I already did that, sorry for not providing any code. Take this as an example:

public struct Wrapper<Element> {
    
    private var elements: [Element]
    
    public init<S: Sequence where S.Iterator.Element == Element>(_ sequence: S) {
        elements = [Element](sequence)
    }
    
}

extension Wrapper: Collection {
    
    public var startIndex: Int { return elements.startIndex }
    public var endIndex: Int { return elements.endIndex }
    
    public func index(after index: Int) -> Int {
        return index + 1
    }
    
    public subscript(position: Int) -> Element {
        return elements[position]
    }
    
}

extension Wrapper: CustomReflectable {
    
    public var customMirror: Mirror {
        return Mirror(self, unlabeledChildren: self, displayStyle: .collection)
    }
    
}

If I debug an instance of this Wrapper type, then Xcode’s Variables View will show

▿ wrapper
  ▿ elements = x values
    [0] = 0
    [1] = …

But the `elements` property is an implementation detail. What I would really want to see is this:

▿ wrapper = x values
  [0] = 0
  [1] = …

But I’m not sure if this is even possible. That’s basically why I’m asking this. Hopefully it’s clearer now :slight_smile:

One last thing to note, the code `dump(wrapper)` will print

▿ 3 elements
  - 1
  - 2
  - 3

to the console, which is good. If I don’t implement CustomReflectable, then `dump(wrapper)` will show this:

▿ Wrapper<Swift.Int>
  ▿ elements: 3 elements
    - 1
    - 2
    - 3

So my CustomReflectable conformance is definitely doing something, but I would like to see the results in the variables view as well.

···

On 27 Jun 2016, at 01:40, Dmitri Gribenko <gribozavr@gmail.com> wrote:

On Fri, Jun 24, 2016 at 3:53 PM, Tim Vermeulen via swift-users > <swift-users@swift.org> wrote:

I’ve implemented a linked list. Now I’d like to be able to view the elements of a linked list in the debugger just like with an array. In the debugger, an array is represented like this:

[0] = the first element
[1] = the second element
etc

I wonder if I can do the same for my linked list. I already implemented CustomReflectable, so the code `dump(myLinkedList)` shows this in the console:

3 elements
- first element
- second elements
- third element

I thought this would also change the appearance of my linked list in the debugger, but unfortunately it’s unchanged. Is there a way to do what I’m trying to do?

Try setting "displayStyle: .collection" when you call the Mirror initializer.

Dmitri

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Dmitri Gribenko) #4

I see. I'm not sure there's a way to hide anything from Xcode's variables view.

+Enrico.

Dmitri

···

On Sun, Jun 26, 2016 at 5:03 PM, Tim Vermeulen <tvermeulen@me.com> wrote:

I already did that, sorry for not providing any code. Take this as an
example:

public struct Wrapper<Element> {

    private var elements: [Element]

    public init<S: Sequence where S.Iterator.Element == Element>(_ sequence:
S) {
        elements = [Element](sequence)
    }

}

extension Wrapper: Collection {

    public var startIndex: Int { return elements.startIndex }
    public var endIndex: Int { return elements.endIndex }

    public func index(after index: Int) -> Int {
        return index + 1
    }

    public subscript(position: Int) -> Element {
        return elements[position]
    }

}

extension Wrapper: CustomReflectable {

    public var customMirror: Mirror {
        return Mirror(self, unlabeledChildren: self, displayStyle:
.collection)
    }

}

If I debug an instance of this Wrapper type, then Xcode’s Variables View
will show

▿ wrapper
  ▿ elements = x values
    [0] = 0
    [1] = …

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Jim Ingham) #5

The display in the variables view uses synthetic child providers:

http://lldb.llvm.org/varformats.html

We could hook up the Mirrors to the synthetic child providers if there is no formatter registered, but Mirrors always run code and we try not to run code for the variables view if we can avoid it as it slows down debugging more than somewhat.

Jim

···

On Jun 26, 2016, at 5:03 PM, Tim Vermeulen via swift-users <swift-users@swift.org> wrote:

I already did that, sorry for not providing any code. Take this as an example:

public struct Wrapper<Element> {
    
    private var elements: [Element]
    
    public init<S: Sequence where S.Iterator.Element == Element>(_ sequence: S) {
        elements = [Element](sequence)
    }
    
}

extension Wrapper: Collection {
    
    public var startIndex: Int { return elements.startIndex }
    public var endIndex: Int { return elements.endIndex }
    
    public func index(after index: Int) -> Int {
        return index + 1
    }
    
    public subscript(position: Int) -> Element {
        return elements[position]
    }
    
}

extension Wrapper: CustomReflectable {
    
    public var customMirror: Mirror {
        return Mirror(self, unlabeledChildren: self, displayStyle: .collection)
    }
    
}

If I debug an instance of this Wrapper type, then Xcode’s Variables View will show

▿ wrapper
  ▿ elements = x values
    [0] = 0
    [1] = …

But the `elements` property is an implementation detail. What I would really want to see is this:

▿ wrapper = x values
  [0] = 0
  [1] = …

But I’m not sure if this is even possible. That’s basically why I’m asking this. Hopefully it’s clearer now :slight_smile:

One last thing to note, the code `dump(wrapper)` will print

▿ 3 elements
  - 1
  - 2
  - 3

to the console, which is good. If I don’t implement CustomReflectable, then `dump(wrapper)` will show this:

▿ Wrapper<Swift.Int>
  ▿ elements: 3 elements
    - 1
    - 2
    - 3

So my CustomReflectable conformance is definitely doing something, but I would like to see the results in the variables view as well.

On 27 Jun 2016, at 01:40, Dmitri Gribenko <gribozavr@gmail.com <mailto:gribozavr@gmail.com>> wrote:

On Fri, Jun 24, 2016 at 3:53 PM, Tim Vermeulen via swift-users >> <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

I’ve implemented a linked list. Now I’d like to be able to view the elements of a linked list in the debugger just like with an array. In the debugger, an array is represented like this:

[0] = the first element
[1] = the second element
etc

I wonder if I can do the same for my linked list. I already implemented CustomReflectable, so the code `dump(myLinkedList)` shows this in the console:

3 elements
- first element
- second elements
- third element

I thought this would also change the appearance of my linked list in the debugger, but unfortunately it’s unchanged. Is there a way to do what I’m trying to do?

Try setting "displayStyle: .collection" when you call the Mirror initializer.

Dmitri

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com <mailto:gribozavr@gmail.com>>*/

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Kate Stone) #6

The display in the variables view uses synthetic child providers:

http://lldb.llvm.org/varformats.html

We could hook up the Mirrors to the synthetic child providers if there is no formatter registered, but Mirrors always run code and we try not to run code for the variables view if we can avoid it as it slows down debugging more than somewhat.

I'd add that running code when trying to display variables can have much more serious effects than just slowing debugging. It allows for arbitrary side effects, which aren't always desirable, and depends on the code execution, which isn't always possible in situations where the target process has deadlocked or crashed.

Writing custom formatters that run in LLDB"s process as described by Jim above is indeed the way to change the default display in the Variables View.

···

On Jun 26, 2016, at 10:56 PM, Jim Ingham via swift-users <swift-users@swift.org> wrote:

On Jun 26, 2016, at 5:03 PM, Tim Vermeulen via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

I already did that, sorry for not providing any code. Take this as an example:

public struct Wrapper<Element> {
    
    private var elements: [Element]
    
    public init<S: Sequence where S.Iterator.Element == Element>(_ sequence: S) {
        elements = [Element](sequence)
    }
    
}

extension Wrapper: Collection {
    
    public var startIndex: Int { return elements.startIndex }
    public var endIndex: Int { return elements.endIndex }
    
    public func index(after index: Int) -> Int {
        return index + 1
    }
    
    public subscript(position: Int) -> Element {
        return elements[position]
    }
    
}

extension Wrapper: CustomReflectable {
    
    public var customMirror: Mirror {
        return Mirror(self, unlabeledChildren: self, displayStyle: .collection)
    }
    
}

If I debug an instance of this Wrapper type, then Xcode’s Variables View will show

▿ wrapper
  ▿ elements = x values
    [0] = 0
    [1] = …

But the `elements` property is an implementation detail. What I would really want to see is this:

▿ wrapper = x values
  [0] = 0
  [1] = …

But I’m not sure if this is even possible. That’s basically why I’m asking this. Hopefully it’s clearer now :slight_smile:

One last thing to note, the code `dump(wrapper)` will print

▿ 3 elements
  - 1
  - 2
  - 3

to the console, which is good. If I don’t implement CustomReflectable, then `dump(wrapper)` will show this:

▿ Wrapper<Swift.Int>
  ▿ elements: 3 elements
    - 1
    - 2
    - 3

So my CustomReflectable conformance is definitely doing something, but I would like to see the results in the variables view as well.

On 27 Jun 2016, at 01:40, Dmitri Gribenko <gribozavr@gmail.com <mailto:gribozavr@gmail.com>> wrote:

On Fri, Jun 24, 2016 at 3:53 PM, Tim Vermeulen via swift-users >>> <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

I’ve implemented a linked list. Now I’d like to be able to view the elements of a linked list in the debugger just like with an array. In the debugger, an array is represented like this:

[0] = the first element
[1] = the second element
etc

I wonder if I can do the same for my linked list. I already implemented CustomReflectable, so the code `dump(myLinkedList)` shows this in the console:

3 elements
- first element
- second elements
- third element

I thought this would also change the appearance of my linked list in the debugger, but unfortunately it’s unchanged. Is there a way to do what I’m trying to do?

Try setting "displayStyle: .collection" when you call the Mirror initializer.

Dmitri

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com <mailto:gribozavr@gmail.com>>*/

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Enrico Granata) #7

Tim,
the Xcode variables view is controlled by a different mechanism than the playgrounds/po - there is a reference for that mechanism at http://lldb.llvm.org/varformats.html
The gist of it is that you're going to want to make a synthetic child provider that returns no child elements for your object - that will be what the variables view picks up

···

On Jun 26, 2016, at 9:41 PM, Dmitri Gribenko <gribozavr@gmail.com> wrote:

On Sun, Jun 26, 2016 at 5:03 PM, Tim Vermeulen <tvermeulen@me.com> wrote:

I already did that, sorry for not providing any code. Take this as an
example:

public struct Wrapper<Element> {

   private var elements: [Element]

   public init<S: Sequence where S.Iterator.Element == Element>(_ sequence:
S) {
       elements = [Element](sequence)
   }

}

extension Wrapper: Collection {

   public var startIndex: Int { return elements.startIndex }
   public var endIndex: Int { return elements.endIndex }

   public func index(after index: Int) -> Int {
       return index + 1
   }

   public subscript(position: Int) -> Element {
       return elements[position]
   }

}

extension Wrapper: CustomReflectable {

   public var customMirror: Mirror {
       return Mirror(self, unlabeledChildren: self, displayStyle:
.collection)
   }

}

If I debug an instance of this Wrapper type, then Xcode’s Variables View
will show

▿ wrapper
▿ elements = x values
   [0] = 0
   [1] = …

I see. I'm not sure there's a way to hide anything from Xcode's variables view.

+Enrico.

Dmitri

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/

Thanks,
- Enrico
:envelope_with_arrow: egranata@.com :phone:️ 27683


(Tim Vermeulen) #8

Hi Enrico,
Thanks for your reply. This means, however, that I can’t easily distribute my code along with this synthetic child provider in a package or a library, correct?

···

On 29 Jun 2016, at 19:16, Enrico Granata <egranata@apple.com> wrote:

Tim,
the Xcode variables view is controlled by a different mechanism than the playgrounds/po - there is a reference for that mechanism at http://lldb.llvm.org/varformats.html
The gist of it is that you're going to want to make a synthetic child provider that returns no child elements for your object - that will be what the variables view picks up

On Jun 26, 2016, at 9:41 PM, Dmitri Gribenko <gribozavr@gmail.com <mailto:gribozavr@gmail.com>> wrote:

On Sun, Jun 26, 2016 at 5:03 PM, Tim Vermeulen <tvermeulen@me.com <mailto:tvermeulen@me.com>> wrote:

I already did that, sorry for not providing any code. Take this as an
example:

public struct Wrapper<Element> {

   private var elements: [Element]

   public init<S: Sequence where S.Iterator.Element == Element>(_ sequence:
S) {
       elements = [Element](sequence)
   }

}

extension Wrapper: Collection {

   public var startIndex: Int { return elements.startIndex }
   public var endIndex: Int { return elements.endIndex }

   public func index(after index: Int) -> Int {
       return index + 1
   }

   public subscript(position: Int) -> Element {
       return elements[position]
   }

}

extension Wrapper: CustomReflectable {

   public var customMirror: Mirror {
       return Mirror(self, unlabeledChildren: self, displayStyle:
.collection)
   }

}

If I debug an instance of this Wrapper type, then Xcode’s Variables View
will show

▿ wrapper
▿ elements = x values
   [0] = 0
   [1] = …

I see. I'm not sure there's a way to hide anything from Xcode's variables view.

+Enrico.

Dmitri

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com <mailto:gribozavr@gmail.com>>*/

Thanks,
- Enrico
:envelope_with_arrow: egranata@.com :phone:️ 27683