"the real kicker is that native modules are still there. They are just reserved for a few Elm contributors only. "
I think the sentence above is not a fair description of the current situation: is not that one from the core team can create his/her own package containing native stuff and publish it, while we can't. They also can't.
Native code is just for developing Elm itself, not its ecosystem. If one day you'll send a PR for a bugfix in the core/String module, you'll probably write some native code and it could be ok.
The comparison to using native in core I feel is quite a fair one. If native is so egregious, why don't the core packages also use ports? Elm's design could totally include a system port, and it could use an API like what Elm users are told to use. (Send Value out of the port and decode its operation and data in JS, and likewise when it comes back into Elm.) Then, aside from what needs to be compiled in Haskell, core packages would not have to use the evil native code either. Win-win, right?
No. The reason is because such a thing is impractical for many core use cases, even if possible. And being that Elm's existing API doesn't even come close to covering all web capabilities, some of the ones that we ordinary Elm users face in our apps are also impractical to do over ports. I've seen several use cases mentioned, such as web sockets, or using popular JS libraries which do not work well with the asynchronous nature of ports. But I'll give my specific use case as an example. The next paragraph is mostly copied from another thread under this post.
The primary thing Elm fails to do for us right now is type-based JSON de/serialization. Elm's built-in encoding and decoding is great for fuzzy APIs. However, that is not a situation we find ourselves in. In 99+% of our internal API types, the server and client types line up exactly 1-to-1. (There is only 1 case where we need to use a decoder.) We adjust these types regularly as we implement new or update existing features. So for us, using encoders and decoders creates hundreds of lines of redundant/difficult code that we have to touch regularly. So maintaining co/decs has only downsides, and there is no non-native way to handle this in Elm. Instead, we define a port (never used), and call the 20 lines of referentially transparent native code to extract the auto-generated encoder or decoder from the port.
My case may be different from most other users, so I don't expect Elm to have this feature right now. Nor a lot of others that people might need. But I would generally expect users are able to reasonably cover their needs. And for that reason native usage in app code compares fairly to native in core code... because in both, it is otherwise impractical (even if still possible) to accomplish some use cases without it. At least for now.
Its eventual removal seems like a good idea. But its removal at this time seems whimsical or even punitive based on Evan's post. This kind of decision raises the risk meter for us on using Elm going forward. Because now we're wondering how much more divergent from today's practical realities subsequent releases will get.
We're a place where coders share, stay up-to-date and grow their careers.
We strive for transparency and don't collect excess data.