more abstract implementation