Reminds me of jwz's Java doc on the topic of final variables, and how the access is restricted by compiler convention, not in the JVM:
System.in, out and err (the stdio streams) are all final
variables. They didn't used to be, but some clever applet-writer
realized that you could change them and start intercepting all output
and do all sorts of nasty stuff. So, the whip-smart folks at Sun went
and made them final. But hey! Sometimes it's okay to change them! So,
they also added System.setIn, setOut, and setErr methods to change
them!
``Change a final variable?!'' I hear you cry. Yep. They sneak in
through native code and change finals now. You might think it'd give
'em pause to think and realize that other people might also want to
have public read-only yet privately writable variables, but no.
Oh, but it gets even better: it turns out they didn't really have to
sneak in through native code anyway, at least as far as the JVM is
concerned, since the JVM treats final variables as always writable to
the class they're defined in! There's no special case for
constructors: they're just always writable. The javac compiler, on the
other hand, pretends that they're only assignable once, either in
static init code for static finals or once per constructor for
instance variables. It also will optimize access to finals, despite
the fact that it's actually unsafe to do so.
Replace System.out with an object that responds to all of the same methods, but which does something clever with them. For instance one that adds timestamps on output, logs stuff somewhere, filters, etc.
This is a very powerful trick. However the downside is that it is in the category of things where only one person gets to be clever. Because the second person to replace that object breaks the first. So they decided to discourage that.
Everything can be redefined interactively at the REPL. Also due to Rich Hickey's mad skills you get pretty much Java method dispatch performance.
EDIT: There is a gross misunderstanding about how this works. The following is invalid and will throw an exception, please take the time to understand this:
user> (ns baz)
baz> (bar-ify "foo")
Your changes will not affect use of java.lang.String in other libs.
I'd like to clarify that Protocols just generate a bunch of functions and a Protocol object (and an interface, but that's an implementation/interop detail). The functions are the interesting things in most cases. However, they're also namespaced like everything else. You can do the following though:
So there is potential for two libraries extending the same things and causing a conflict if the semantics differ, but I'm not too concerned about that. It would be rather rude to extend someone else's protocol to cover someone else's java class without documenting that you do so.
Why's this worth noting? There's no reason you shouldn't be able to extend a type with methods to support a new interface, no matter what that type's author intended. It's not in any sense "dangerous" to existing APIs, as changing final variables could potentially be. It seems like completely natural behavior.
It's not in any sense "dangerous" to existing APIs
If your job is to deliver and maintain such an API, then by allowing subclassing you have a larger contract you have to maintain when you want to make changes to the underlying class: rather than just the public interface, you also need to worry about the protected interface. If your API is new, you may want to shepherd your users (by marking a class as final) to favor composition over inheritance to maximize your ability to evolve the implementation in ways that don't break.
by allowing subclassing you have a larger contract you have to maintain when you want to make changes to the underlying class: rather than just the public interface, you also need to worry about the protected interface.
In other words, if you allow subclassing, then you also have to worry about the interface that you have explicitly marked visible to subclasses.
Normally a non-problem, by definition.
final is useful when sealing a class that inherits from a parent class with a protected interface, but even if "final" is reduced to an annotation (or even a comment), its presence explicitly limits your end of the API contract.
Except if the public api of foo lib is only functions, which is the case for all clojure libs i've worked with.
EDIT: Ha, i just stumbled on this old yegge article, which is quite appropriate i think. With clojure APIs you think in verbs, so nouns are not that important
"In the remotest regions, beyond the Functional Kingdoms, lies a fabled realm called Lambda the Ultimate. In this place it is said that there are no nouns at all, only verbs!"
"In the remotest regions, beyond the Functional Kingdoms, lies a fabled realm called Lambda the Ultimate. In this place it is said that there are no nouns at all, only verbs!"
I already live in that Kingdom, so when I say "members", I mean member variables or member functions.
It does neither. The dispatch logic is on the protocol side, which can be modified. When a class is extended, the protocol function is changed to have an extra instance check. (I don't understand the details in full, though. You'll need to ask Rich Hickey)
AFAIK there is also some kind of caching involved to improve performance.