EXEC GO should work exactly as it does.
Let me try to explain from my point a view. Lets break down what we are asking SQL to do:
First we create a procedure called "Go". (Not good naming but perfectly ok in the eyes of SQL). The procedure "GO" contains the following:
CREATE PROC GO AS
BEGIN
EXEC ('ALTER PROC GO AS SELECT NULL')
EXEC GO
DROP PROC GO
END
GO
Now the statement GO after the "END" statement. What does GO do here? Go is not a T-SQL statement. It is interpreted as a signal that they code above it should be sent as a batch of Transact-SQL statements.
Now SQL has been told to execute what we just sent with the statement
EXEC GO and it does...
The SQL engine executes the procedure:
ALTER the procedure and in this case executes the select statement "SELECT NULL" (you could have but any select statement here). This in turn puts a NULL in the return buffer so to speak. The next statement does exactly what it was told to do. The last step in the SP is to delete itself and it does. A NULL is still in the buffer and is returned.
Just my 2 cent worth.