[ruby-core:32665] Re: Proposal for Optional Static Typing for Ruby

From: Eleanor McHugh <eleanor@...>
Date: 2010-10-01 12:02:13 UTC
List: ruby-core #32665
On 1 Oct 2010, at 02:33, Martin Pilkington wrote:
> Hi Ellie
>=20
> What do you mean by runtime mutable? Do you mean creating new classes =
or methods at runtime? Do you mean creating a new class at runtime? Do =
you mean adding a method to an existing class at runtime? Swapping the =
implementation of two methods? Loading new code at any point during =
runtime? All of those are things that Objective-C can do. The only thing =
you can't do is to interpret a string containing Obj-C as code, as while =
Obj-C is heavily runtime based, it is still a pre-compiled language =
(that said it is theoretically possibly in the future for such JIT =
compilation to occur).
>=20
> Yet despite being very dynamic, it also gives the ability for type =
information to be added prior to compilation, so tools can use it to =
help aid developers.

Martin,

I've clearly outlined what runtime mutability is in the context of Ruby. =
It's the ability to arbitrarily and with bound to make changes to the =
type space of a program without any reference to the shape of that type =
space at the time the change occurs. The techniques you mention are a =
subset of that, and as I stated in my previous response any language =
_can_ be used this way through abuse of function and void pointers, or =
similar abstractions. However that's analogous to Greenspun's Law: every =
significant program includes a buggy, half-arsed implementation of Lisp =
;)

In Ruby such ad hoc abuse is possible, but it's not necessary because =
the language exposes the full power of its compilation facilities via =
eval and its relatives. Ruby is essentially Lisp for a world of Objects =
as opposed to Abstract Data Types.

You really need to allow time for Ruby's actual type system to settle =
fully in your head to appreciate the full implications of this, =
otherwise you're going to keep labouring under the misguided impression =
that nominal typing is a significant factor in designing and debugging =
Ruby code. I know that experience in compiled and statically typed =
languages suggests this should be the case, but it just isn't. Their =
type systems are fundamentally different.

In Ruby the use of nominal type-checking leads to brittle code that can =
and will break the basic expectations of experienced Ruby developers. We =
have Object::kind_of? which can be used to enforce such constraints but =
I don't know a single experienced Rubyist who doesn't consider it a code =
smell for precisely this reason.


Ruby eval, module_eval and instance_eval can each be used to reshape =
type space - ranging from the global shape to individual details - with =
very little effort.

I'm sorry to keep coming back to this notion of type space, but in this =
context it is very important as Ruby objects are better understood as =
coalesced groups of type information than by reference to Class or =
similar nominal typing concepts. A Ruby object is generally (but not =
necessarily) a member of a set of isomorphic types with the class =
information that you'd recognise in Objective-C or Java actually acting =
more as a partial derivative on the multi-dimensional set of isomorphic =
types which it expresses on any given inspection.

Let me put this another way. If a Ruby object were a person then the =
apparent nominal class upon inspection might be the hat that they've =
decided to wear, but that wouldn't prevent them from swapping hats to =
suit the occasion or from wearing completely unsuitable shoes at the =
same time. Under normal circumstances a Ruby program might well ask =
whether the object is wearing a hat, and then as we know that hats have =
a certain shape and set of interactions with their environment we can =
decide to check its colour or flip the brim if it has one.

Now it's not important whether or not all Ruby objects behave like this =
all the time. It's only important that for significant objects in a Ruby =
program they're likely to behave like this enough of the time - popping =
on hats, taking off coats, swapping cups of tea with their associates - =
that the correctness of the overall program is determined by the =
structural types through which they interact and not by a platonic ideal =
which thanks to isomorphism might be cognate with an infinite number of =
other platonic ideals whose interactions are indistinguishable in a =
particular context.

The set of nominal types embodied by a given structural type is =
infinite. Accepting this and making it productive for the individual =
programmer is a basic axiom of Ruby's design. The language takes a small =
performance hit for this, and it scares the hell out of those used to =
thinking largely in terms of nominal typing, but the payoff is in =
allowing more flexible and general design: in essence we trade a modest =
amount of additional processing power and of developer effort in =
understanding Ruby code for a huge reduction in the amount of code =
required - often an orders of magnitude reduction. That means having to =
remember far fewer details of type space and far fewer lines of code =
which leads to a net gain in effectiveness.

Please don't think I'm arguing that better dev tools which allow us to =
reason about Ruby code in new and powerful ways aren't desirable. They =
obviously are. But to add more insight than they do unnecessary =
verbosity they need to focus on understanding Ruby as is and not on =
constraining Ruby developers to think in the same way as they might in C =
or Java. That would be the worst of both worlds: slower runtime =
performance than statically compiled code but without any of the =
productivity boost or elegance of exposition that we currently associate =
with Ruby.

And as I've previously mentioned, the place to look for inspiration in =
designing such tools is in other languages with unbounded eval and =
higher-order typing, such as Lisp or Forth.

I'll shut up now.


Ellie

Eleanor McHugh
Games With Brains
http://feyeleanor.tel
----
raise ArgumentError unless @reality.responds_to? :reason



In This Thread