While I can see all of your mentioned pain points I don’t think they should be changed. The (primary) interface for a protocol is calling Prot.to_s not having a X.to_s. I’m not sure why you’d want to have X.wrap as a private function in the struct. Either you keep Prot and X independant, but then X needs to expose all the functionality Prot needs (publically) or you don’t and you can just implement Prot.to_s directly by moving the implementation of wrap into the protocol.
Elixir itself even goes so far in that DateTime.to_string and String.Chars.to_string(date_time) duplicate the implementation. The latter doesn’t call DateTime.to_string.


















