# Silent change (bug?) of Join after v9

Consider the following sample:

Join[{A[x]}, {A[x]}, 2]


It causes Join::headsd warning in and before v9 and returns the input:

Join::headsd: Expression {A[x]} at position 1 is expected to have head List for all subexpressions through level 2.

But gives the following output without warning at least since v11.2:

(* {A[x, x]} *)


What's funny is, it's mentioned in the Details of Join since v10, that:

The $$\text{list}_i$$ do not need to have head List, but must all have the same head.

So my question is, is this an intentional change i.e. a mistake in the document of Join, or a bug of Join?

If it's intentional, is it possible to bring back the old behavior?

If it's a bug, what's the easiest fix for it?

• Yeah, joining over arbitrary heads can produce strange results sometimes. I'd also prefer to have a way to restore the old behavior. – Henrik Schumacher Oct 19 '18 at 7:58
• @HenrikSchumacher Thanks to the change, I'm now struggling to convince this guy that his understanding for high dimensional list in Mathematica is wrong. – xzczd Oct 19 '18 at 11:20
• That was precisely the first post that I thought of when I read your post here! =D – Henrik Schumacher Oct 19 '18 at 11:23
• To the downvoter, I am interested in what's wrong with my question, would you please elaborate. I'm not trying to complain here, I just want improve my question if possible. – xzczd Oct 23 '18 at 16:29
• It is worth to include this incompatible change into this listing: mathematica.stackexchange.com/a/56729/280 – Alexey Popkov Oct 27 '18 at 5:48

This is perhaps more an extended comment than an answer, as I haven't provided any fixes/workarounds.

1. A certain behavior changed in a way you consider a bug.
2. The documentation supports your claim that this is a bug.

## Claim 1

I can't really argue with claim 1, as it's subjective, even though I personally see it as perfectly reasonable to be able to do Join[{A[x]}, {A[x]}, 2] and get {A[x,x]}. If you strongly disagree with this, I'd be interested to better understand why. I do sympathize if this is causing older code to break. One could perhaps imagine an option which toggles the old functionality, but alas, that does not presently exist.

## Claim 2

As far as claim 2, I read the line in the docs that "all must have the same head" as applying to each level separately. I think the change to the text of Join::headsd at least partially supports this -- Join::headsd is now

Expression 1 at position 2 is expected to have head 3 for all expressions at level 4

Note that through has been changed to at.

But then, the change to this message seems to ignore heads at outer levels, which still matter. E.g., Join[head1[A[x]], head2[A[x]], 2] gives a much less sensible warning:

Join::headsd Expression head2[A[x]] at position 2 is expected to have head head1 for all expressions at level 2

(This might be a bug in the warning mechanism -- I would have expected it to say at level 1)

• I didn't notice the words can be understood in this way. Then I would argue that the explanation in the document is ambiguous, and the new headsd warning is undoubtedly half-baked. – xzczd Oct 24 '18 at 8:06

To be honest it does not seem to me that there is anything wrong with Join. Actually, it has been generalized in the latest versions. In essence Join allows you to join two (or more) objects of the same structure, but not objects of different structure. The structure has to be the same up to the level where you want to make the junction. All this seems to me quite desirable and acceptable.

Consider these examples:

1- we try to join a-objects...no problem

In[9]:= Join[a[b[c[1]]], a[d[c[2]]], 1]

Out[9]= a[b[c[1]], d[c[2]]]


2- now we try to join an ab-object with an ac-object...error!

In[8]:= Join[a[b[1]], a[c[2]], 2]


During evaluation of In[8]:= Join::headsd: Expression a[c[2]] at position 2 is expected to have head b for all expressions at level 2.

Out[8]= Join[a[b[1]], a[c[2]], 2]


3- now we try to join an abc-object with an adc-object...error! even though the a and the c heads are the same for both objects.

In[6]:= Join[a[b[c[1]]], a[d[c[2]]], 3]


During evaluation of In[6]:= Join::headsd: Expression a[d[c[2]]] at position 2 is expected to have head b for all expressions at level 3.

Out[6]= Join[a[b[c[1]]], a[d[c[2]]], 3]


But there is no problem in joining abc-objects, because they have the same structure, up to 3rd level (the joining level)

In[11]:= Join[a[b[c[d[1]]]], a[b[c[2]]], 3]

Out[11]= a[b[c[d[1], 2]]]

• "It does not seem to me that there is anything wrong with Join. " As said by Shredderroy in the comment above, "The fact that many of the built-in functions treat expressions of the form Head[arg1, arg2...] uniformly regardless of the actual head, can be a blessing and a curse. " The change for Join is understandable, but it also undoubtedly make code more error-prone. – xzczd Oct 26 '18 at 14:05