API: MultiIndex.names|codes|levels returns tuples
- [ ] closes #53531 (Replace xxxx with the GitHub issue number)
- [ ] [Tests added and passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#writing-tests) if fixing a bug or adding a new feature
- [ ] All [code checks passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#pre-commit).
- [ ] Added [type annotations](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#type-hints) to new arguments/methods/functions.
- [ ] Added an entry in the latest `doc/source/whatsnew/vX.X.X.rst` file if fixing a bug or adding a new feature.

Just playing devil's advocate but why would we prefer tuple here over `Index`? The latter is what we return from DataFrame.columns which maybe should harmonize with this > Just playing devil's advocate but why would we prefer tuple here over Index?

I picked tuple to align with the prior `FrozenList` which seemed to act like an immutable `list`. If we were to go with `Index` I think each would have to be `Index[object]

* `MultiIndex.codes` would be an Index of ndarrays
* `MultiIndex.levels` would be an Index of Indexes
* `MultiIndex.names` would be an Index of object/inferred dtype which would be reasonable.

But yeah the biggest thing is that the returned object should not be able to be resized. Will merge this week unless there's any objections @mroeschke - just the request to fix the docs: https://github.com/pandas-dev/pandas/pull/57042#discussion_r1472031470 > @mroeschke - just the request to fix the docs: [#57042 (comment)](https://github.com/pandas-dev/pandas/pull/57042#discussion_r1472031470)

Ah thanks for the reminder. Removed This is quite a breaking change .. I know you knew this and therefore kept it for 3.0, but I still do wonder if this is worth the breakage, and if we really want to change it, whether we couldn't first deprecate some aspects of it.

The breaking change I ran into with geopandas, is the fact that a tuple cannot be concatenated like a list. We actually used the same pattern in pandas itself, as the diff in this PR has this change in the groupby code:

```diff
-        mi = MultiIndex(levels=levels, codes=codes, names=idx.names + [None])
+        mi = MultiIndex(levels=levels, codes=codes, names=list(idx.names) + [None])
```

I can imagine quite some external libraries use this when manipulating index / multi-index objects. 

We could first deprecate those methods on FrozenList that won't work anymore for tuple (I see @rhshadrach mentioned the same on the issue for the `difference`/`union` methods)

