I could replicate the problem with various shells under FreeBSD, GNU/Linux, and Solaris. It had me head-scratching for more than an hour, so I decided to post the question here
alternative:
echo foo | (read a ; echo $a)
Edit:
If you need $a outside the subshell, you have to reverse the commands:
read a < <(echo foo); echo $a
this way the read is executed in the current process
I came up with a solution that doesn't hide the variable values in a subshell, and that can also work with multiple values.
set `echo foo bar`
A=$1
B=$2