# Logically equivalent Through expressions, but one produces an error

I have a list of three lists of strings. Thus, MatchQ[{{__String}, {__String}, {__String}}] is True. I would like to extract all the strings which are present in the first two lists but not in the third.

According to the documentation, the following two expressions using Through should be logically equivalent. Yet, the first one runs without error, while the second one produces the message shown below, before producing the correct output anyway:

ClearAll[lst];
lst = {CharacterRange["a", "h"], CharacterRange["d", "k"], CharacterRange["g", "n"]};

lst // Through[{Most /* Apply[Intersection], Last}[#]] & // Apply[Complement]
(* Output: {d, e, f} *)

lst // Through[Complement[Most /* Apply[Intersection], Last][#]] &
(*
Complement::normal: Nonatomic expression expected at position 2 in Complement[Most/*Apply[Intersection],Last].
{d, e, f}
*)


Why is the second expression generating an error message?

• Isn't this exactly the same as the first expression (which does not produce an error)? The operator @@ is the same as Apply. I am trying to understand why the second one would produce an error message, since the documentation suggests that I should be able to apply the head Complement in Through directly. – Shredderroy Nov 5 '18 at 19:25

Through does not have any Hold attributes:

Attributes[Through]


{Protected}

Hence, Complement tries to evaluate before Through performs its function. For a simpler example:

Through[Complement[Most, Rest][Range[10]]]


Complement::normal: Nonatomic expression expected at position 1 in Complement[Most,Rest].

{1}

Since Complement[Most, Rest] doesn't evaluate, Through will still do its thing, and then Complement will evaluate. Another way of seeing this is to give Through the HoldAll attribute:

SetAttributes[Through, HoldAll]
Through[Complement[Most, Rest][Range[10]]]
ClearAttributes[Through, HoldAll]


{1}

No error messages.

• Thanks a lot for the explanation. – Shredderroy Nov 5 '18 at 20:10
• Is there any conceivable benefit to not having this as the default setting? Why would the designers have chosen not to give Through the HoldAll attribute? – Shredderroy Nov 5 '18 at 20:23