diff -u <(echo foo) <(cat) doesn't work in an interactive bash because commands in process substitution are not put in the foreground so can't read from the terminal device. Like in cat & where cat is also run in background (not in the foreground process group of the terminal device), the process running cat is suspended with a SIGTTIN signal as soon as it tries to read from its controlling terminal.
echo hello | diff -u <(echo ok ) <(cat)' works because the whole pipeline made of two subshells is in foreground, and anyway cat is reading from the pipe, not the terminal. The process substitutionsubstitutions end up being in foreground because they were started by the subshell (the second component of that pipeline) that is in foreground.
bash-5.0$ diff -u <(echo ok ) <(ps -o pid,ppid,pgid,args)
--- /dev/fd/63 2021-11-12 22:39:41.985207894 +0000
+++ /dev/fd/62 2021-11-12 22:39:41.985207894 +0000
@@ -1 +1,6 @@
-ok
+ PID PPID PGID COMMAND
+ 9779 9772 9779 /bin/zsh
+1957388 9779 1957388 bash --norc
+1958861 1957388 1957388 bash --norc
+1958862 1957388 1958862 diff -u /dev/fd/63 /dev/fd/62
+1958863 1958861 1957388 ps -o pid,ppid,pgid,args
bash-5.0$ (diff -u <(echo ok ) <(ps -o pid,ppid,pgid,args))
--- /dev/fd/63 2021-11-12 22:42:04.761112701 +0000
+++ /dev/fd/62 2021-11-12 22:42:04.761112701 +0000
@@ -1 +1,6 @@
-ok
+ PID PPID PGID COMMAND
+1960605 9772 1960605 /bin/zsh
+1960612 1960605 1960612 bash --norc
+1960757 1960612 1960757 diff -u /dev/fd/63 /dev/fd/62
+1960759 1960757 1960757 bash --norc
+1960760 1960759 1960757 ps -o pid,ppid,pgid,args
It's back to being OK as then we start a whole subshell in foreground.
So the easy work around here is to run the pipeline in a subshell.
In any case, again, that only applies to interactive shells (where terminal job control is being performed) and when stdin is the controlling terminal of the session.
In scripts (and you generally only care about portability in scripts), there's no problem with diff -u <(echo ok) <(cat) even when stdin is a terminal as the shell is non-interactive and doesn't do job control.
That cat however does nothing useful, it's the same UUOC as in:
cat | diff -u <(echo ok) -
Or
cat | diff -u <(echo ok) /dev/stdin
On systems that don't support /dev/fd/x / /dev/stdin¹, for commands which unlike diff, don't support - to specify stdin, <(cat) in bash or zsh (but not in ksh versions prior to ksh93u where that feature comes from) uses a temporary named pipe instead, so diff -u <(echo ok) <(cat) will still work on those systems.
¹ very few these days and there are probably far more systems without bash than without /dev/fd/x