Let's clarify some things first:
- Expansion is manipulation of the input stream. This can happen either by expanding a macro (i.e. replacing it by its definition, possibly with arguments) or by expanding an expandable primitive (like
\ifx).
- Execution is manipulating the properties of the TeX engine. This can happen through non-expandable primitives (like
\def) or assignments. These properties affect how the TeX engine behaves in the future.
- In the usual metaphor, both expansion and execution happen in the mouth of the TeX engine. This is, however, not everything TeX does (otherwise we would never get a document). When the engine finds the letter
a, for example, at the start of the input stream, it will swallow it. That is, it will (usually) put the glyph "a" of the currently selected font in the document (skipping a lot of detail here).
Now, we often want to store some piece of input stream away for later use, most notably in macros (for use in the same TeX run) and in files (usually for use in a later TeX run)1. Let's concentrate on the former.
Rather than just storing some piece of input string in a macro that we typed in the source code before compiling, it is often useful to store the expansion of something instead (like the current page number), which we can do with \edef. Note that we are "storing pieces of input stream", nothing else. We cannot store the state of the entire TeX engine in a macro (what would expanding that even mean?). It doesn't make sense to say "let's store the execution of this". Thus, \edef fully expands its argument, but does not execute anything (as does \write).
As noted by David Carlisle in his comment, this really is the "normal" mode for a macro expansion language. All that other business of execution and swallowing the TeX engine does is something else entirely. Only doing expansion should thus be quite natural.
1This is not really the same, of course, as the definition of a macro consists of tokens but the content of a file consists of characters, but let's not get hung up on that.
If you think about it, this is really the only way to go about it. In your question you proposed also doing execution in these contexts, but what would that even mean? If I did
\edef\foo{\def\baz{asdf}}
what would be the expansion of \foo? Should \baz be defined now? What should
\write\@auxout{\color{blue}Hello}
write to the aux file? Should text following this \write be blue?
I'm sure one could find more absurd examples, but in the end it comes down to this: You are storing a piece of input stream, so only input stream manipulation (i.e. expansion) should be performed during this operation. If some definition is necessary for the expansion you are aiming for, do that outside of this operation, e.g.
{\def\foo{baz}
\immediate\write\@auxout{I just wanted to say \foo.}
}
As a final note, there are of course other places where an expansion-only context occurs. For example, when TeX expects a number, it will expand everything until it finds something unexpandable that can't be part of the number anymore. Also doing execution there would not make any sense.
\section{\protect\foo{}}? (I cannot really answer why\sectionwas defined in the way it is. However,\protectallows you to avoid the complications you are describing here.) – Jun 12 '20 at 05:32\protectwon't work. This thread is related but more fundamental. I think I do have to understand why\sectionis defined in the way it is. To be honest, I think this is a huge bug. I wouldn't think it works in this way. But there may be different ideas. – Cyker Jun 12 '20 at 05:35\sectionwas "executed", and there must be means to deal with delicate cases. These means exist, whether the way things are done is always the most intuitive way is a different question. – Jun 12 '20 at 05:46\textsf, say? – Jun 12 '20 at 07:20\textsfis defined. But if it is used in moving arguments then I guess it is fine just leave it there. – Cyker Jun 12 '20 at 07:27tocfile, aren't we? What should it do with\textsf{pft}or\textcolor{\mycolor}{abc}? Wouldn't it be reasonable if it expanded\mycolorin the second case, but kept\textcolorunexpanded? Or\textsuperscipt{\mysuperscript}? You can't just "expand" these fully when you write them to thetocfile. – Jun 12 '20 at 07:32\textcolorand\mycolorif you really want to do it. – Cyker Jun 12 '20 at 07:50#definesystem. The really weird tex-specific execution model is the intertwined macro expansion and evaluation that it normally does, with macro expansion happening "just in time" to produce enough tokens for the next primitive execution. – David Carlisle Jun 12 '20 at 08:21