I see your point that overriding a core class would never be
recommended. However, the compiler can never be sure that nobody will
ever do it. Since the consequences are pretty bad, I would be really
uncomfortable if the compiler's behavior in that case were not
explicitly and unambiguously defined. While the current behavior isn't
the best for convenience, it's at least unambiguous and prevents the
worst cases.
Thanks for considering alternatives. What consequence would be worse than SC self-destructing? The only possibility I can come up with is if SC is permitted to run despite detecting a class clash, so that now one of my favorite objects has been replaced with its evil doppelganger, and SC no longer behaves as I expected. That might arguably be worse than SC just dying. Two suggestions: first - in any class clash with a core SC object, always use the core SC code; second - print a warning (this already happens) noting the conflicting files. This would have two side-effects in addition to making SC more robust (IMO). First, developers would be actively discouraged from overriding a core class. Second, a user seeing a clash between a 3rd party piece of code and a core SC object would be empowered to quickly move the offending code to its final resting place ;)
At the very least, there needs to be an order of priorities between
the main library folder, system extensions and user extensions. That's
easy enough. The real problem is if you have duplicates at the same
level (both definitions at user extension level, e.g.).
That is the most important question, since it's hard to prevent this situation, even with the best of intentions.
Then, the
choice is basically arbitrary, and I would say it should not be up to
the compiler to choose one magically (how? Alphabetically, random?).
So maybe compilation is okay unless there's a clash at the same level,
then it would have to fail. Maybe also a list of core class names that
would always be illegal to override -- if overrides for these classes
are found in extensions, they would be ignored, and if found in the
main lib, again there's no choice but to fail compilation totally.
I still don't think it's necessary for compilation to fail in this case. I like your suggestion of alphabetically making the choice, since it would be consistent (though the random approach might be funnier). But the important point is to warn the user that a clash has occurred. From that point on it's up to the user to resolve the problem. Why do I like this approach better than death by class conflict? Because it gives me more choice as a user. For example, the main reason I fired up the 3.3 alpha was to check out some groovy new GUI stuff that was being trumpeted as worthy of note. The clashes I reported above killed SC straight out, distracting me from why I had opened the alpha in the first place. It would have been much better if I could have just noted that there was a class clash that had nothing to do with the part of SC that I wanted to explore. Then I could have gone on directly to look at the GUI stuff, and later come back to resolve the unrelated BEQ class conflict, probably much later, when 3.3 is officially released. To my mind, it's purely a question of improving the user experience.
Conflicting method extensions at the same level have the same problem.
I was surprised, for instance, when I had wslib installed, to find out
that my postSorted got dumped in favor of Wouter's :) Nothing
critical there, just cosmetic, but it's a flaw that the user doesn't
have a choice what to do in that case.
One thing I've been doing is to prepend all of my classes with "EL" for example "ELSoundRecording". So far my classes have not needed to fight off interlopers :) Maybe that approach could be used to protect methods too. Or perhaps some more sophisticated scheme for protecting the name-space; anyway that's another topic...
Eric