On 9/30/2010 7:52 PM, Eleanor McHugh wrote:
> It appears that this proposal would require the runtime to add a new layer to for checking the posited nominal type annotations which perforce could be invoked at any point during program execution and indeed possibly repeatedly during the lifetime of that execution. Bearing in mind that nominal type is not the primary determinant of object validity or code correctness in Ruby, and that there are already existing methods for confirming nominal type identity (more of that anon) it's not at all clear that type annotations on this model would be a noticeable improvement.

Syntactically they would be. Documentation-wise, they would be as well. 
Tooling-wise, they would aid in some *basic* (keyword: basic) code 
comprehension and analysis. IDE's, for instance, would have useful 
information to communicate back to the programmer, be it warnings or for 
code completion.

Secondly I should point out that type-checking need not be implemented 
by the VM-- having the type annotations would give a Ruby developer a 
standard way in which to implement such type checking themselves, 
without resorting to ugly undocumentable DSLs as we've seen in this 
thread (ie. "def_with_types"). I think that's a big win in itself. We've 
recently seen Method#parameters get introduced into 1.9.2 from the 
nudging of real-world usage in merb/rails to route via given parameter 
names. Imagine what else could be done if, for instance, the route knew 
of the expected parameter *type* as well (again, without resorting to 
DSL)? I see plenty of room for improvement in this space.

> With Ruby you're free to play with the raw type-space in its full glory, and that introduces certain fundamental limitations on just how much you can definitively say about that type-space at any given point in time.

I still don't see an actual incompatibility here. Yes, there will be 
times when type annotations will be less useful, but I don't see the 
logical step in saying: "because type annotations are not always useful, 
they are *never* useful." Ruby certainly gives you lots of freedom, but 
as far as I've seen, most of the real world still uses that 80% of Ruby 
that does not bend any space-time continuums. Correct me if I'm wrong. 
Those annotations could be applied there with great benefit.

> Annotations might well be useful markers in some circumstances, but just as in QM an observation causes the quantum world to collapse into classical reality so with Ruby you run the risk of collapsing back into a static nominal type system with all that entails.

I'm not sure I buy this comparison. Adding *optional* type annotations 
is unlikely to reduce Ruby's expressiveness down to that of Java unless 
you make *improper* use of the type annotation syntax (and iff you 
actually use type annotations at all). In a properly designed system, 
however, you're not actually losing any freedom, you're simply enforcing 
rules that would have otherwise been defined in business logic (type 
checking, object dispatch). For example, if you have method foo that 
takes param x and you call `x.reduce` inside foo, you're not 
"collapsing" any expressiveness reality by enforcing that x be of 
duck-type #reduce. The same idea would go for any code that would "raise 
unless type.is_a?(Foo)"-- which happens to be a lot of code. Whether or 
not the latter is a valid idiom is, as I said before, an 
opinionated/stylistic discussion for another thread.

> I appreciate this is a very high-level analysis so I'll bring this down to earth.
>
> In essence every Ruby object is first and foremost an instance of its own singleton class backed up by a superposition of classes, meta-classes and modules from which that singleton class draws its specific character. Any of these elements might be reloaded or redefined at any time using appropriate hooks in the runtime. Duck-typing allows us to conveniently overlook this fact by focusing on what usually matters to us when we're reasoning about our code: whether or not an object responds to the messages we're interested in sending it, and how to elegantly recover when in fact that message is inappropriate - either through runtime exception handling or by capturing the message with method_missing and performing some fallback operation.
>
> In this model runtime type checking and method overloading can already be performed with Object::kind_of?, but the type guarantee is localised to a particular expression in the code and subsequent expressions may change the nominal type of the object in question. As such it's a brittle idiom because it captures only a snapshot of the full system state.

I'm not sure I see a problem with this either. Can you provide an actual 
example that shows why you would need full system state to do run-time 
type checking or run-time method dispatch involving method overloading? 
It doesn't seem to me that knowing the "full" system state is necessary.

As I see it, method dispatch would simply need to be updated so that 
before the VM passes a method call to an object, it searches the method 
best matching the given parameters (comparing the parameters' 
"kind_of?"/"respond_to?" against the given type annotations, be they 
class/mixins or duck-types). Note that this would be precisely what 
people do now when implementing overloading, except that it would be 
offloaded onto the VM, providing a little bit of performance (not that 
relevant), but more importantly, a much more eloquent syntax.

> It's possible that Ruby's semantics could be expanded to use kind_of? individually or in combination as a guard expression, freezing a given object for the duration of the expression so that it becomes type invariant and allowing optimised code to be produced. The same pattern could also likely be used with responds_to? to optimise method calls. Both of these changes would seem more in keeping with the Ruby Way than explicit type annotations as proposed, although I'd be loathe to see either implemented without considerable proof that they would indeed benefit Ruby and not lead to the brittleness and fragility so often associated with nominal typing. Otherwise Ruby would become a less expressive language to the detriment of all of us.
>
>

You're focusing a lot on compiler optimizations, and you only seem to 
point out that there are complications with such optimizations (not 
surprising), but you didn't really tackle any problems with the other 
benefits I listed. Personally, I see compiler optimization as the least 
worthwhile benefit here, and I wouldn't really mind taking that out of 
the list entirely.

To be clear, I wouldn't want Ruby to be less expressive OR lose the 
typing benefits it already has. If compiler optimizations introduced 
those realities, I would be against it too. However, as I mentioned, 
performance is not the only benefit of type annotations.

- Loren