Now, the thing I like about implicit has-a relationships is that they guarantee less code than making it explicit, in that they're the same amount of code sans type declarations and checks. For example, the above would be simply
(def dump-out (port l)
(map [wrie _ port] l))
No typeclass declarations and no type checking. This also has the advantage of being identical to the code you'd write if you were completely unaware of a scanner abstraction.
Also, on a more philosophical level, I feel like type checking is just out of place in a dynamically-typed language like Arc.
...which ends up being the optimizing compiler's clue:
(def dump-out (port l)
; a completely optional declaration
; for:
; (1) an non-optimizing interpreter, so that
; you have some chance of checking errors, and
; (2) the optimizing compiler, so that it can
; do some shortcuts.
(type-declaration l 'scanner)
(map [write _ port] l))
^^
You can then trivially redefine type-declaration as:
(= type-declaration
(annotate 'mac nilfn))
To disable type-checking.
Oh and yeah: type checking is plenty in-place, if you're building a library. If the library's interface functions simply passed the object to library-internal code without checking, the error will pop up as coming from some code deep in your library, where your user might be less inclined to trace (because it might be your bug, not theirs). At least if you do the check on the interface functions themselves you have proof that the bug is in the user's code.
But that macro, and the whole plumbing behind declaring and checking type classes, just don't have to exist if you make it implicit. It's a lot of added complexity for no gain in power. All you gain is a little type safety - and if you need type safety, Arc (and Lisp in general) is not your language.
I wonder how much type-checking major Lisp libraries really do have. In the dynamically-typed-language libraries I've looked at, there are more or less no type checks. In the Ruby community, they're specifically discouraged, because they limit the power of duck typing.
Yes, but who says it has to be used? In the majority of code, there won't be type checking, but we do want to say something like this:
This function accepts a list of ordinal types
which we can simply put in-code as:
(type-declaration a 'Scanner)
(type-declaration (car a) 'Ordinal)
The point is that the function doesn't specifically accept a list of strings or numbers - it accepts a traversable sequence of anything that can be ordered. The type-declaration thing is just a notation to express that to someone else.