refactor join to prepare for different implementations