return empty MultiIndex for symmetrical difference on equal MultiIndexes
State: closed

 - [X] closes #13490
 - [X] tests added / passed
 - [X] passes ``git diff upstream/master --name-only -- '*.py' | flake8 --diff``


Labels:
name: Bug
name: MultiIndex

Comments:
Some of your style changes caused linting errors: https://travis-ci.org/pandas-dev/pandas/jobs/235803966#L1385

```
pandas/core/indexes/base.py:184:25: E127 continuation line over-indented for visual indent
pandas/core/indexes/base.py:194:23: E127 continuation line over-indented for visual indent
pandas/core/indexes/base.py:298:37: E127 continuation line over-indented for visual indent
pandas/core/indexes/base.py:904:38: E127 continuation line over-indented for visual indent
pandas/core/indexes/base.py:1466:13: E122 continuation line missing indentation or outdented
pandas/core/indexes/base.py:1467:13: E122 continuation line missing indentation or outdented
pandas/core/indexes/base.py:3374:45: E127 continuation line over-indented for visual indent
pandas/core/indexes/base.py:3392:13: E128 continuation line under-indented for visual indent
pandas/core/indexes/base.py:3670:29: E127 continuation line over-indented for visual indent
pandas/core/indexes/base.py:3746:17: E122 continuation line missing indentation or outdented
pandas/core/indexes/base.py:3747:17: E122 continuation line missing indentation or outdented
pandas/core/indexes/base.py:3764:17: E122 continuation line missing indentation or outdented
pandas/core/indexes/base.py:3765:17: E122 continuation line missing indentation or outdented
pandas/core/indexes/base.py:3772:21: E122 continuation line missing indentation or outdented
pandas/core/indexes/base.py:3773:21: E122 continuation line missing indentation or outdented
pandas/core/indexes/base.py:3912:29: E127 continuation line over-indented for visual indent
```
# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=h1) Report
> Merging [#16486](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/97ad3fb9c87226ad983267e2891dbbf68432b8ea?src=pr&el=desc) will **decrease** coverage by `50.23%`.
> The diff coverage is `22.22%`.

[![Impacted file tree graph](https://codecov.io/gh/pandas-dev/pandas/pull/16486/graphs/tree.svg?token=eZ4WkYLtcO&src=pr&width=650&height=150)](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=tree)

```diff
@@             Coverage Diff             @@
##           master   #16486       +/-   ##
===========================================
- Coverage    90.4%   40.17%   -50.24%     
===========================================
  Files         161      161               
  Lines       51033    51035        +2     
===========================================
- Hits        46136    20501    -25635     
- Misses       4897    30534    +25637
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `?` | |
| #single | `40.17% <22.22%> (-0.01%)` | :arrow_down: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/indexes/base.py](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhlcy9iYXNlLnB5) | `56.39% <22.22%> (-39.35%)` | :arrow_down: |
| [pandas/io/sas/sas\_constants.py](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=tree#diff-cGFuZGFzL2lvL3Nhcy9zYXNfY29uc3RhbnRzLnB5) | `0% <0%> (-100%)` | :arrow_down: |
| [pandas/types/concat.py](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=tree#diff-cGFuZGFzL3R5cGVzL2NvbmNhdC5weQ==) | `0% <0%> (-100%)` | :arrow_down: |
| [pandas/parser.py](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=tree#diff-cGFuZGFzL3BhcnNlci5weQ==) | `0% <0%> (-100%)` | :arrow_down: |
| [pandas/tslib.py](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=tree#diff-cGFuZGFzL3RzbGliLnB5) | `0% <0%> (-100%)` | :arrow_down: |
| [pandas/tools/hashing.py](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=tree#diff-cGFuZGFzL3Rvb2xzL2hhc2hpbmcucHk=) | `0% <0%> (-100%)` | :arrow_down: |
| [pandas/io/sas/sas7bdat.py](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=tree#diff-cGFuZGFzL2lvL3Nhcy9zYXM3YmRhdC5weQ==) | `0% <0%> (-90.67%)` | :arrow_down: |
| [pandas/io/sas/sas\_xport.py](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=tree#diff-cGFuZGFzL2lvL3Nhcy9zYXNfeHBvcnQucHk=) | `0% <0%> (-90.28%)` | :arrow_down: |
| [pandas/core/tools/numeric.py](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvdG9vbHMvbnVtZXJpYy5weQ==) | `10.44% <0%> (-89.56%)` | :arrow_down: |
| [pandas/io/json/normalize.py](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=tree#diff-cGFuZGFzL2lvL2pzb24vbm9ybWFsaXplLnB5) | `8.16% <0%> (-88.78%)` | :arrow_down: |
| ... and [112 more](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=footer). Last update [97ad3fb...743aa47](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=h1) Report
> Merging [#16486](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/92d07992e826808cd56f0bd8fec083b510ca402d?src=pr&el=desc) will **increase** coverage by `<.01%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/pandas-dev/pandas/pull/16486/graphs/tree.svg?height=150&width=650&token=eZ4WkYLtcO&src=pr)](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master   #16486      +/-   ##
==========================================
+ Coverage   90.75%   90.75%   +<.01%     
==========================================
  Files         161      161              
  Lines       51071    51073       +2     
==========================================
+ Hits        46348    46351       +3     
+ Misses       4723     4722       -1
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `88.59% <100%> (ø)` | :arrow_up: |
| #single | `40.11% <0%> (-0.01%)` | :arrow_down: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/indexes/multi.py](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhlcy9tdWx0aS5weQ==) | `96.64% <100%> (+0.08%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=footer). Last update [92d0799...6c67a4a](https://codecov.io/gh/pandas-dev/pandas/pull/16486?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

@Tafkas sorry if the above conversation about `_shallow_copy` wasn't clear. I think the idea is to revert the changes in `core/indexes/base.py` and only change `MultiIndex._shallow_copy` in `core/indexes/multi.py`. That's where the new if block can go

```python
            if len(values) == 0:
                return MultiIndex(levels=[[] for _ in range(self.nlevels)],
                                  labels=[[] for _ in range(self.nlabels)], **kwargs)
```

Can you also add a couple tests with metadata (names)? I think the rule is to propagate names if they are the same on either index. So

```python
def test_multiindex_symmetric_difference(self):
    idx = MultiIndex.from_product([['a', 'b'], ['A', 'B']],
                                  names=['a', 'b'])
    result = idx ^ idx
    assert result.names == idx.names

    idx2 = idx.copy().rename(['A', 'B'])
    result = idx ^ idx
    assert result.names == [None, None]
```

Do you have a chance to make those changes?
@TomAugspurger sure I can do that. But what about the case if values is None?
Then it should do whatever it's doing now. The new case should only apply when the sym diff is empty.
@Tafkas if you can rebase / update, we can merge this before 0.20.2 is release (end of the week)
lgtm. ping on green.
thanks!