Explicit Structural Typing (Duck Typing)
I have always liked structural typing of interfaces (as found in Go and Scala), but I also like nominative typing of interfaces (as found in C# and Java). I kept switching back and forth between the two approaches when I realized that the middle ground was to provide a more powerful type coercion operator, by overloading the "as" operator.
Structural typing is when an object can be cast to an interface (or signature or trait, depending on your language) if the structure matches. For example: the object provides implementations of the methods required by an interface. This feature is implemented in languages like Go , OCaML , and Scala to name a few.
Nominative typing is the opposite of structural typing, where all subtype relationships must be explicit.
Many of us (including me) often conflate duck typing and structural typing. Duck typing, according to some, should only be used to refer to dynamic languages. I am not so sure that that is fair. I think that including structural typing under the duck typing umbrella would be reasonable, since its functionality is more or less the same, and the core concept is the same.
Anyway, the point of this post is that I like both nominative and structural typing, and could never choose between the two approaches for Heron. Over the last five years, Heron has swung back and forth a couple of times.
In huge mission-critical systems developed by large teams of people, over many years, the nominative typing approach makes sense. It seems to be more robust, more explicit, and more maintainable. For smaller, more agile systems, and certain programming paradigms the structural typing approach makes more sense.
I finally found a middle ground: explicit structural typing via a coercion operator.
Heron has an operator called "as" which at first appears like the C# operator of the same namesake. It can be used to convert an object into its type, or any of its subtypes, including any of the interfaces it explicitly implements.
Unlike C#, it cannot be used to perform downcasts. In other words you cannot cast an object to a base-class and back. This is on purpose, and I'll talk about it some other time.
However, the "as" operator in the latest release of Heron (version 0.8.1 ) now also will coerce an object into any interface that it satisfies. At run-time the object is checked, and an adapter object is made. To see it in action check out the test-duck-typing.heron file.
I think that this is a pretty descent compromise between structural and nominative typing: you can declare interfaces and will get implicit casts if you do, otherwise you can always use "as" to force an object to match an interface, giving you all the syntactic nicety of dynamic languages.